diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/community/fortios | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
84 files changed, 33118 insertions, 0 deletions
diff --git a/ansible_collections/community/fortios/.github/workflows/ansible-test.yml b/ansible_collections/community/fortios/.github/workflows/ansible-test.yml new file mode 100644 index 000000000..84667383f --- /dev/null +++ b/ansible_collections/community/fortios/.github/workflows/ansible-test.yml @@ -0,0 +1,117 @@ +# README FIRST +# 1. If you don't have unit tests remove that section +# 2. If your collection depends on other collections ensure they are installed, see "Install collection dependencies" +# If you need help please ask in #ansible-devel on Freenode IRC + +name: CI +on: + # Run CI against all pushes (direct commits, also merged PRs), Pull Requests + push: + pull_request: + schedule: + - cron: '0 6 * * *' +env: + NAMESPACE: community + COLLECTION_NAME: fortios + +jobs: + +### +# Sanity tests (REQUIRED) +# +# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html + + sanity: + name: Sanity (Ⓐ${{ matrix.ansible }}) + strategy: + matrix: + ansible: + # It's important that Sanity is tested against all stable-X.Y branches + # Testing against `devel` may fail as new tests are added. + - stable-2.9 + - stable-2.10 + - devel + runs-on: ubuntu-latest + steps: + + # ansible-test requires the collection to be in a directory in the form + # .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/ + + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + # it is just required to run that once as "ansible-test sanity" in the docker image + # will run on all python versions it supports. + python-version: 3.8 + + # Install the head of the given branch (devel, stable-2.10) + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + - name: Install collection dependencies + run: ansible-galaxy collection install fortinet.fortios -p . + + # run ansible-test sanity inside of Docker. + # The docker container has all the pinned dependencies that are required + # and all python versions ansible supports. + - name: Run sanity tests + run: ansible-test sanity --docker -v --color + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + +### +# Unit tests (OPTIONAL) +# +# https://docs.ansible.com/ansible/latest/dev_guide/testing_units.html + + units: + runs-on: ubuntu-latest + name: Units (Ⓐ${{ matrix.ansible }}) + strategy: + # As soon as the first unit test fails, cancel the others to free up the CI queue + fail-fast: true + matrix: + ansible: + - stable-2.9 + - stable-2.10 + - devel + + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + # it is just required to run that once as "ansible-test units" in the docker image + # will run on all python versions it supports. + python-version: 3.8 + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + # OPTIONAL If your unit test requires Python libraries from other collections + # Install them like this + - name: Install collection dependencies + run: ansible-galaxy collection install fortinet.fortios -p . + + # Run the unit tests + - name: Run unit test + run: ansible-test units -v --color --docker --coverage + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + # ansible-test support producing code coverage date + - name: Generate coverage report + run: ansible-test coverage xml -v --requirements --group-by command --group-by version + working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + + # See the reports at https://codecov.io/gh/GITHUBORG/REPONAME + - uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: false diff --git a/ansible_collections/community/fortios/CHANGELOG.rst b/ansible_collections/community/fortios/CHANGELOG.rst new file mode 100644 index 000000000..315ee7cff --- /dev/null +++ b/ansible_collections/community/fortios/CHANGELOG.rst @@ -0,0 +1,23 @@ +=============================== +community.fortios Release Notes +=============================== + +.. contents:: Topics + + +v1.0.0 +====== + +Release Summary +--------------- + +This is the first stable release version of ``community.fortios`` after migrating from ``community.network``. + +v0.1.0 +====== + +Release Summary +--------------- + +This is the first pre-release version of ``community.fortios`` after migrating from ``community.network``. + diff --git a/ansible_collections/community/fortios/FILES.json b/ansible_collections/community/fortios/FILES.json new file mode 100644 index 000000000..ff661f230 --- /dev/null +++ b/ansible_collections/community/fortios/FILES.json @@ -0,0 +1,705 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f68abff78f63afb5352c766e4db7ad5d175c7f694457f2366d9a7298add2fecd", + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/ansible-test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "19a6b3f421c758dcb1cff0df8b7b88d1c65102f67c681ff73df7a6ccbb568b7e", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f", + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/httpapi", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/httpapi/fortianalyzer.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "648481e036a0932efec67ba2e420184c301e686ac033c6f0b0264db2355bcd3c", + "format": 1 + }, + { + "name": "plugins/httpapi/fortimanager.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6ed4256edb77f5d249af3c5cd4712895e5983d30769e39cc55bb1b9d03ab4052", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/fortianalyzer", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/fortianalyzer/fortianalyzer.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b0ff3d65975da31f0c7cb047020d4c6d46f3c89a79540d0b1247b2915ea0c4c6", + "format": 1 + }, + { + "name": "plugins/module_utils/fortianalyzer/common.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6360ba52a6cfece6d1019a007a2e6eacfa27e4f336dad9ded728e2503a29b5e8", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/fmgr_ha.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "464c7846058120a915d8f3cf01a0f6d9837a27fa9a2891387542621034dcc83b", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwobj_ippool6.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "26f13eec55001dd57ef6d95776d5837b9d46a471093bd1935e24c3a58cfbaf62", + "format": 1 + }, + { + "name": "plugins/modules/faz_device.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c8839a63bee525f35cffe283a77db7f3652d28821fa264616df887b19b9b54b7", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwobj_service.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "47e80e81bc707b110b8e4ffc3eac0015452c776a0883f1803500f9a5c9023914", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_wanopt.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bf283ffb49c0eab3f2a9a38217f2808106318cff95065e6a978fb0c034a43e4f", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_script.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8ce447194af97e4edc1043b8016aef69ed69490f03a0d4c41d16db290a114792", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_profile_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2e9fe286983a0e0173ab745643105a859fa1ee3f1a00609c2ebd7bb5a58e7213", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwpol_package.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bc6a6339e096178f17cd1d65c0473f755355ce7ec0dfaa37d3091fedb3a4ff56", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwpol_ipv4.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac7471486a82d16b5270dbc46dbb252d6936a44bd990d8160eaacde7f3ba07d5", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_ssl_ssh.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f9cc56f146984b5a3b8aa1ad2979f2cca998f66a11dab249fae1b23ea1c219d0", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_av.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ef51293e7d255b88fea7362657b24c84b24d5ba2233a287472ba761f6037566e", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_device_provision_template.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "77b7ece676c515c4f119bd23c22a9d36c3a790a7af102dd4ff7d66ad2b2fe46c", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_waf.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cd2150060ab3e48aeeb26da90920cf8d2546391113031138a3da9ebe50fd7cc0", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_device.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bb4095f2afb5ecfa8b1e329510b5e73d88a1c8a154258b5211f677c0048ee172", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_device_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d4d288abdb2c8c7cfa6a05782e780e00952b671661422a3a42784aeb00109f5", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_voip.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "32416e5d4d45cbf3914f95928ea1927aa674bee30fad18b100952b031bd0d32d", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwobj_vip.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f2bebf470e60ac32e1a67036775096788b133f5d6875c04889ba27cd25ddab0d", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwobj_ippool.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a3f00e23fbd59441239df895739833423b076a450bd408973ab95acf3d3eadb8", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_spam.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e10c57eb626ea19a2eae26aadf66855240ad89d5b0a6413b377f4634296a8ed6", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_fwobj_address.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b61853c936ca55809f64d50eccfe5785273761499ecfd5e09990d6d392f082b2", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_appctrl.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "baf802fe6fb4a51abd42b71918111b7f2a729e94d7e44badb379c2725784d0c4", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_proxy.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4afb0d6aa33741f82ace5765afadfb148a5554b79e71b289af4fc5618171995c", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_query.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b2cf28b5ba7f3fe79b46fa00b300a98fcfd5053970f700b0a716d39fd0022a74", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_provisioning.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "320d318aa0597fd33e7af67a0ea73f4eef6ebe654b1b615b7376c7ab9dd52aa1", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_web.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1bc99ba796b46e37c01f1d56b0b03c56b6e1b51185d90707c14143dc4946d128", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_dns.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "be27960fb24a6cf7a0b28c22a162c6d11e597f2a7b5dc5cd472e7bd35c2aeb62", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_secprof_ips.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b1e5ed9b5a781e70de17d09d44aa9969c11d9d87b11c3516a0eff9b551d9ce37", + "format": 1 + }, + { + "name": "plugins/modules/fmgr_device_config.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e56d4cb2afe812e977686ce3e8e612a1547f9d08b3e0b8027e9a79ec4a0da8a2", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.10.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "976f414f52ce7b547a43998ea1762723c53d4de828dc166f602be16f2651217c", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.9.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e6f4fcc6ef6baadfa69a5b0f3e68370e28f37476eccf83f1d0c1aef93544c65e", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.11.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "976f414f52ce7b547a43998ea1762723c53d4de828dc166f602be16f2651217c", + "format": 1 + }, + { + "name": "tests/requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ba070b64632b89e1bef218788ded4fc3bf17ccb402ca9e35d40a3a1653ab94d5", + "format": 1 + }, + { + "name": "tests/unit", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/compat", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/compat/mock.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0af958450cf6de3fbafe94b1111eae8ba5a8dbe1d785ffbb9df81f26e4946d99", + "format": 1 + }, + { + "name": "tests/unit/compat/unittest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096", + "format": 1 + }, + { + "name": "tests/unit/compat/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/unit/plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0a575e95971ecd816770d0042b105ebdbfa55a933132c07348cffd57e6140d0d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/test_fmgr_device.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "512852b623272348359d5c22b4d656eaf32614d592da774771dad99407acb24b", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7115c96deb7d4167ddbd5ae70d4fbc7e0054868e4a495d21e1a2c1e94914c269", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7cd5c8a06c531dacd219e2d028ebe9d68d854b9220aaec0e4931c44799077b88", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fixtures/test_fmgr_ha.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a8248aea277e191f77dbe58514c4af20625bd4fa7408496dac0a962b571b8dd", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwpol_package.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "602ee00b0c287dd299d1d9597e7f68e85fd5d054210c840bcec4a25dd924455e", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwobj_service.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bcdfa628009e77f693216bb434077e79fa3810d0e49f75361600122a56836d6e", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7d9177b4957df48428a7e2b3c36548844d48a5d487980edc076df69b55f41c2e", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwobj_address.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a9c11ea2ed943e513d7a2806008f1684badb007831bc0b91a34b51edeb46ae8c", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_script.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9a9a91a01073dd4285e9ba8dae75d5dbe76d75eb1c3e0d11fc6a9fa8ee3f899a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/fortimanager_module.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0f68461fc5f2da4e97dfcf93c6e9d9921f96b00b1bd7c30357953500adccfbcf", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_voip.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "caf96e930ad2240f4a32284c2bf5d2991fd39fda7a384fc54412d106cef8104b", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_device_provision_template.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f5b87afcc6b8d888c343ee7508b6fb553cc2afaa0c5320a2b677c943547d61cd", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_web.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd159e7e3dad055fa172f13ab0357cccbe65d623f433efdf746eaf098ad0d2a6", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_device.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "912c1b107ace5ea1ed73b6f9def4a2d12a2d1bf39e8758ac1f79724418e18f6f", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_provisioning.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5727db87650d9eeaeacb052f453a6a5f10d01ed5aee6e4bd3e1347cd943bb98a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_query.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8cc43dbeb28f2bff9b787804cfacd1414ae0ff720e67a8cb97bdc58d93f41b9d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14a0e799bb15516eb787fd04a341388fe6c70ac4f27a6dc1cba70586299a90f6", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/utils.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14ef338777c48584d98782de3939389d48469b8293f31e288570764d76dfed77", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3f5dcaafa90af79c97d8e09945cf88d9c28b04957b9e247f503ce66d2241b75", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_waf.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b91c96acdf10048def0c296dec10e535ea1c38c68433352172f09612295d0a4d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_av.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "77940e90f6496a6e010de0875ea42a06f72e4622e503c69e388060860da47074", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_proxy.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "786e86942d08f2181665d19f215ca9a2008753b643cfbd4e16d01f554e16826d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_spam.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8f20bcd65f4c73ace45ef9728be4c1d82468aa610068836a1fa9b7c1c58bbe0", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwobj_vip.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "97f9738e78513c52c9c64e6a144c6f2b63642d35b0e33c778ea02d06f7c91de9", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_device_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0448c4dc400cb579424f01b021f6a33f51c701d661921dcb5626fc225bf929d6", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_dns.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cea0267cea12a15e96bd02e97dc27f6491b785070e7822aae571abc585271643", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9ff2e6a7fc744ccab91b2c702f6fd2f2527445a71630b78d240fb4e2230fa1b2", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_ha.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d6ddf2c8a841b3186c81abcfac5bdb66d5e855feb23c4fb3f00daa1fd36b4f0a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_device_config.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8401c3be5e4adff10719e9b2c1434f14d275c7e5a01db7fa8ff1be786c85c4c3", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "156710761420a3a12195b257997fb2886ee55eeada45d01e53379ab307a29d4c", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_secprof_ips.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "502a60c2e7793b235792e30aa852a12d36aa1938dffb201f8853f0d105bb9c1e", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7df6a3c135a5bce1b7907a7446a7afb947d84ad0f18459ab9c597a983e52eddf", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d23d38cd8739f947d2961ec5472c47999d9ef50aa6393c58834132eed7f5a57a", + "format": 1 + }, + { + "name": "tests/unit/requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "48ada20ce37d554c681d979a24be9fb42d23f5a7c065161191636eab7cfcf02a", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.keep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7140e78998772ced00b93cd84d98708f056b1ab5738ce3957f56185bd17272e8", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aa39cb2256d5c5d10e56f79a5d481f7834fd9cdec126ed0e60f3d23c14cf514a", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9946eb44edaffa74dca585845d08650fdae505de464a43714d4a88d641c1fc31", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/community/fortios/LICENSE b/ansible_collections/community/fortios/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/ansible_collections/community/fortios/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/ansible_collections/community/fortios/MANIFEST.json b/ansible_collections/community/fortios/MANIFEST.json new file mode 100644 index 000000000..e9644bc2c --- /dev/null +++ b/ansible_collections/community/fortios/MANIFEST.json @@ -0,0 +1,36 @@ +{ + "collection_info": { + "namespace": "community", + "name": "fortios", + "version": "1.0.0", + "authors": [ + "Luke Weighall (github.com/lweighall)", + "Andrew Welsh (github.com/Ghilli3)", + "Jim Huber (github.com/p4r4n0y1ng)" + ], + "readme": "README.md", + "tags": [ + "community", + "fortios" + ], + "description": "modules for management of FortiOS devices", + "license": [], + "license_file": "LICENSE", + "dependencies": { + "ansible.netcommon": ">=1.0.0", + "fortinet.fortios": ">=1.0.0" + }, + "repository": "https://github.com/ansible-collections/community.fortios", + "documentation": null, + "homepage": "https://github.com/ansible-collections/community.fortios", + "issues": "https://github.com/ansible-collections/community.fortios/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "49d0dc8fba167a3485191481126c7429bcd64d3ddc8733bdc1c94fdd05757fb1", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/community/fortios/README.md b/ansible_collections/community/fortios/README.md new file mode 100644 index 000000000..a3a0353c8 --- /dev/null +++ b/ansible_collections/community/fortios/README.md @@ -0,0 +1,99 @@ +# community.fortios Collection +<!-- Add CI and code coverage badges here. Samples included below. --> +[![CI](https://github.com/ansible-collections/community.fortios/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.fortios/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.fortios)](https://codecov.io/gh/ansible-collections/community.fortios) + +<!-- Describe the collection and why a user would want to use it. What does the collection do? --> + +This repo hosts the `community.fortios` Ansible Collection. + +The collection includes a variety of Ansible content to automate the management of FortiOS devices. + +## Tested with Ansible + +<!-- List the versions of Ansible the collection has been tested with. Must match what is in galaxy.yml. --> + +- `2.9` +- `2.10` +- `devel` + +## External requirements + +<!-- List any external resources the collection depends on, for example minimum versions of an OS, libraries, or utilities. Do not list other Ansible collections here. --> + +- None + +<!-- ### Supported connections --> + +<!-- Optional. If your collection supports only specific connection types (such as HTTPAPI, netconf, or others), list them here. --> + +## Included Content + +- **Modules**: + - `faz_device` + - `fmgr_device` + - `fmgr_device_config` + - `fmgr_device_group` + - `fmgr_device_provision_template` + - `fmgr_fwobj_address` + - `fmgr_fwobj_ippool` + - `fmgr_fwobj_ippool6` + - `fmgr_fwobj_service` + - `fmgr_fwobj_vip` + - `fmgr_fwpol_ipv4` + - `fmgr_fwpol_package` + - `fmgr_ha` + - `fmgr_provisioning` + - `fmgr_query` + - `fmgr_script` + - `fmgr_secprof_appctrl` + - `fmgr_secprof_av` + - `fmgr_secprof_dns` + - `fmgr_secprof_ips` + - `fmgr_secprof_profile_group` + - `fmgr_secprof_proxy` + - `fmgr_secprof_spam` + - `fmgr_secprof_ssl_ssh` + - `fmgr_secprof_voip` + - `fmgr_secprof_waf` + - `fmgr_secprof_wanopt` + - `fmgr_secprof_web` + +## Using this collection + +<!--Include some quick examples that cover the most common use cases for your collection content. --> + +See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details. + +## Contributing to this collection + +<!--Describe how the community can contribute to your collection. At a minimum, include how and where users can create issues to report problems or request features for this collection. List contribution requirements, including preferred workflows and necessary testing, so you can benefit from community PRs. If you are following general Ansible contributor guidelines, you can link to - [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html). --> + +[Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html) + +## Release notes + +See the [changelog](https://github.com/ansible-collections/community.fortios/tree/main/CHANGELOG.rst). + +<!-- ## Roadmap --> + +<!-- Optional. Include the roadmap for this collection, and the proposed release/versioning strategy so users can anticipate the upgrade/update cycle. --> + +## More information + +<!-- List out where the user can find additional information, such as working group meeting times, slack/IRC channels, or documentation for the product this collection automates. At a minimum, link to: --> + +- [Ansible Collection overview](https://github.com/ansible-collections/overview) +- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html) +- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html) +- [Ansible Collections Checklist](https://github.com/ansible-collections/overview/blob/master/collection_requirements.rst) +- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) +- [The Bullhorn (the Ansible Contributor newsletter)](https://us19.campaign-archive.com/home/?u=56d874e027110e35dea0e03c1&id=d6635f5420) +- [Changes impacting Contributors](https://github.com/ansible-collections/overview/issues/45) + +## Licensing + +<!-- Include the appropriate license information here and a pointer to the full licensing details. If the collection contains modules migrated from the ansible/ansible repo, you must use the same license that existed in the ansible/ansible repo. See the GNU license example below. --> + +GNU General Public License v3.0 or later. + +See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text. diff --git a/ansible_collections/community/fortios/changelogs/changelog.yaml b/ansible_collections/community/fortios/changelogs/changelog.yaml new file mode 100644 index 000000000..0a0e43d15 --- /dev/null +++ b/ansible_collections/community/fortios/changelogs/changelog.yaml @@ -0,0 +1,18 @@ +ancestor: null +releases: + 0.1.0: + changes: + release_summary: 'This is the first pre-release version of ``community.fortios`` + after migrating from ``community.network``. + + ' + fragments: + - summary.yaml + release_date: '2021-01-14' + 1.0.0: + changes: + release_summary: This is the first stable release version of ``community.fortios`` + after migrating from ``community.network``. + fragments: + - release.yaml + release_date: '2021-01-18' diff --git a/ansible_collections/community/fortios/changelogs/config.yaml b/ansible_collections/community/fortios/changelogs/config.yaml new file mode 100644 index 000000000..91b6532af --- /dev/null +++ b/ansible_collections/community/fortios/changelogs/config.yaml @@ -0,0 +1,29 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +keep_fragments: false +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: community.fortios +trivial_section_name: trivial diff --git a/ansible_collections/community/fortios/changelogs/fragments/.keep b/ansible_collections/community/fortios/changelogs/fragments/.keep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/fortios/changelogs/fragments/.keep diff --git a/ansible_collections/community/fortios/meta/runtime.yml b/ansible_collections/community/fortios/meta/runtime.yml new file mode 100644 index 000000000..2ee3c9fa9 --- /dev/null +++ b/ansible_collections/community/fortios/meta/runtime.yml @@ -0,0 +1,2 @@ +--- +requires_ansible: '>=2.9.10' diff --git a/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py b/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py new file mode 100644 index 000000000..0e59ea48e --- /dev/null +++ b/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py @@ -0,0 +1,453 @@ +# Copyright (c) 2018 Fortinet and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +name: fortianalyzer +short_description: HttpApi Plugin for Fortinet FortiAnalyzer Appliance or VM. +description: + - This HttpApi plugin provides methods to connect to Fortinet FortiAnalyzer Appliance or VM via JSON RPC API. + +''' + +import json +from ansible.plugins.httpapi import HttpApiBase +from ansible.module_utils.basic import to_text +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import BASE_HEADERS +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods + + +class HttpApi(HttpApiBase): + def __init__(self, connection): + super(HttpApi, self).__init__(connection) + self._req_id = 0 + self._sid = None + self._url = "/jsonrpc" + self._host = None + self._tools = FAZCommon + self._debug = False + self._connected_faz = None + self._last_response_msg = None + self._last_response_code = None + self._last_data_payload = None + self._last_url = None + self._last_response_raw = None + self._locked_adom_list = list() + self._locked_adoms_by_user = list() + self._uses_workspace = False + self._uses_adoms = False + self._adom_list = list() + self._logged_in_user = None + + def set_become(self, become_context): + """ + ELEVATION IS NOT REQUIRED ON FORTINET DEVICES - SKIPPED + :param become_context: Unused input. + :return: None + """ + return None + + def update_auth(self, response, response_data): + """ + TOKENS ARE NOT USED SO NO NEED TO UPDATE AUTH + :param response: Unused input. + :param response_data Unused_input. + :return: None + """ + return None + + def login(self, username, password): + """ + This function will log the plugin into FortiAnalyzer, and return the results. + :param username: Username of FortiAnalyzer Admin + :param password: Password of FortiAnalyzer Admin + + :return: Dictionary of status if it logged in or not. + """ + + self._logged_in_user = username + self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, "sys/login/user", + passwd=password, user=username,)) + + if "FortiAnalyzer object connected to FortiAnalyzer" in self.__str__(): + # If Login worked then inspect the FortiAnalyzer for Workspace Mode, and it's system information. + self.inspect_faz() + return + else: + raise FAZBaseException(msg="Unknown error while logging in...connection was lost during login operation..." + " Exiting") + + def inspect_faz(self): + # CHECK FOR WORKSPACE MODE TO SEE IF WE HAVE TO ENABLE ADOM LOCKS + status = self.get_system_status() + if status[0] == -11: + # THE CONNECTION GOT LOST SOMEHOW, REMOVE THE SID AND REPORT BAD LOGIN + self.logout() + raise FAZBaseException(msg="Error -11 -- the Session ID was likely malformed somehow. Contact authors." + " Exiting") + elif status[0] == 0: + try: + self.check_mode() + if self._uses_adoms: + self.get_adom_list() + if self._uses_workspace: + self.get_locked_adom_list() + self._connected_faz = status[1] + self._host = self._connected_faz["Hostname"] + except Exception: + pass + return + + def logout(self): + """ + This function will logout of the FortiAnalyzer. + """ + if self.sid is not None: + # IF WE WERE USING WORKSPACES, THEN CLEAN UP OUR LOCKS IF THEY STILL EXIST + if self.uses_workspace: + self.get_lock_info() + self.run_unlock() + ret_code, response = self.send_request(FAZMethods.EXEC, + self._tools.format_request(FAZMethods.EXEC, "sys/logout")) + self.sid = None + return ret_code, response + + def send_request(self, method, params): + """ + Responsible for actual sending of data to the connection httpapi base plugin. Does some formatting as well. + :param params: A formatted dictionary that was returned by self.common_datagram_params() + before being called here. + :param method: The preferred API Request method (GET, ADD, POST, etc....) + :type method: basestring + + :return: Dictionary of status if it logged in or not. + """ + + try: + if self.sid is None and params[0]["url"] != "sys/login/user": + try: + self.connection._connect() + except Exception as err: + raise FAZBaseException( + msg="An problem happened with the httpapi plugin self-init connection process. " + "Error: " + to_text(err)) + except IndexError: + raise FAZBaseException("An attempt was made at communicating with a FAZ with " + "no valid session and an incorrectly formatted request.") + except Exception: + raise FAZBaseException("An attempt was made at communicating with a FAZ with " + "no valid session and an unexpected error was discovered.") + + self._update_request_id() + json_request = { + "method": method, + "params": params, + "session": self.sid, + "id": self.req_id, + "verbose": 1 + } + data = json.dumps(json_request, ensure_ascii=False).replace('\\\\', '\\') + try: + # Sending URL and Data in Unicode, per Ansible Specifications for Connection Plugins + response, response_data = self.connection.send(path=to_text(self._url), data=to_text(data), + headers=BASE_HEADERS) + # Get Unicode Response - Must convert from StringIO to unicode first so we can do a replace function below + result = json.loads(to_text(response_data.getvalue())) + self._update_self_from_response(result, self._url, data) + return self._handle_response(result) + except Exception as err: + raise FAZBaseException(err) + + def _handle_response(self, response): + self._set_sid(response) + if isinstance(response["result"], list): + result = response["result"][0] + else: + result = response["result"] + if "data" in result: + return result["status"]["code"], result["data"] + else: + return result["status"]["code"], result + + def _update_self_from_response(self, response, url, data): + self._last_response_raw = response + if isinstance(response["result"], list): + result = response["result"][0] + else: + result = response["result"] + if "status" in result: + self._last_response_code = result["status"]["code"] + self._last_response_msg = result["status"]["message"] + self._last_url = url + self._last_data_payload = data + + def _set_sid(self, response): + if self.sid is None and "session" in response: + self.sid = response["session"] + + def return_connected_faz(self): + """ + Returns the data stored under self._connected_faz + + :return: dict + """ + try: + if self._connected_faz: + return self._connected_faz + except Exception: + raise FAZBaseException("Couldn't Retrieve Connected FAZ Stats") + + def get_system_status(self): + """ + Returns the system status page from the FortiAnalyzer, for logging and other uses. + return: status + """ + status = self.send_request(FAZMethods.GET, self._tools.format_request(FAZMethods.GET, "sys/status")) + return status + + @property + def debug(self): + return self._debug + + @debug.setter + def debug(self, val): + self._debug = val + + @property + def req_id(self): + return self._req_id + + @req_id.setter + def req_id(self, val): + self._req_id = val + + def _update_request_id(self, reqid=0): + self.req_id = reqid if reqid != 0 else self.req_id + 1 + + @property + def sid(self): + return self._sid + + @sid.setter + def sid(self, val): + self._sid = val + + def __str__(self): + if self.sid is not None and self.connection._url is not None: + return "FortiAnalyzer object connected to FortiAnalyzer: " + to_text(self.connection._url) + return "FortiAnalyzer object with no valid connection to a FortiAnalyzer appliance." + + ################################## + # BEGIN DATABASE LOCK CONTEXT CODE + ################################## + + @property + def uses_workspace(self): + return self._uses_workspace + + @uses_workspace.setter + def uses_workspace(self, val): + self._uses_workspace = val + + @property + def uses_adoms(self): + return self._uses_adoms + + @uses_adoms.setter + def uses_adoms(self, val): + self._uses_adoms = val + + def add_adom_to_lock_list(self, adom): + if adom not in self._locked_adom_list: + self._locked_adom_list.append(adom) + + def remove_adom_from_lock_list(self, adom): + if adom in self._locked_adom_list: + self._locked_adom_list.remove(adom) + + def check_mode(self): + """ + Checks FortiAnalyzer for the use of Workspace mode + """ + url = "/cli/global/system/global" + code, resp_obj = self.send_request(FAZMethods.GET, + self._tools.format_request(FAZMethods.GET, + url, + fields=["workspace-mode", "adom-status"])) + try: + if resp_obj["workspace-mode"] == "workflow": + self.uses_workspace = True + elif resp_obj["workspace-mode"] == "disabled": + self.uses_workspace = False + except KeyError: + self.uses_workspace = False + except Exception: + raise FAZBaseException(msg="Couldn't determine workspace-mode in the plugin") + try: + if resp_obj["adom-status"] in [1, "enable"]: + self.uses_adoms = True + else: + self.uses_adoms = False + except KeyError: + self.uses_adoms = False + except Exception: + raise FAZBaseException(msg="Couldn't determine adom-status in the plugin") + + def run_unlock(self): + """ + Checks for ADOM status, if locked, it will unlock + """ + for adom_locked in self._locked_adoms_by_user: + adom = adom_locked["adom"] + self.unlock_adom(adom) + + def lock_adom(self, adom=None, *args, **kwargs): + """ + Locks an ADOM for changes + """ + if adom: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lock/" + else: + url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/lock" + code, respobj = self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url)) + if code == 0 and respobj["status"]["message"].lower() == "ok": + self.add_adom_to_lock_list(adom) + return code, respobj + + def unlock_adom(self, adom=None, *args, **kwargs): + """ + Unlocks an ADOM after changes + """ + if adom: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/unlock/" + else: + url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/unlock" + code, respobj = self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url)) + if code == 0 and respobj["status"]["message"].lower() == "ok": + self.remove_adom_from_lock_list(adom) + return code, respobj + + def commit_changes(self, adom=None, aux=False, *args, **kwargs): + """ + Commits changes to an ADOM + """ + if adom: + if aux: + url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom) + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/commit/" + else: + url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/commit" + return self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url)) + + def get_lock_info(self, adom=None): + """ + Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible + for some reason, then unlock it. + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/lockinfo" + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lockinfo/" + else: + url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom) + datagram = {} + data = self._tools.format_request(FAZMethods.GET, url, **datagram) + resp_obj = self.send_request(FAZMethods.GET, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. Error: " + to_text(resp_obj))) + elif code == 0: + try: + if resp_obj[1]["status"]["message"] == "OK": + self._lock_info = None + except Exception: + self._lock_info = resp_obj[1] + return resp_obj + + def get_adom_list(self): + """ + Gets the list of ADOMs for the FortiAnalyzer + """ + if self.uses_adoms: + url = "/dvmdb/adom" + datagram = {} + data = self._tools.format_request(FAZMethods.GET, url, **datagram) + resp_obj = self.send_request(FAZMethods.GET, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to get the ADOM Info. Error: " + to_text(resp_obj))) + elif code == 0: + num_of_adoms = len(resp_obj[1]) + append_list = ['root', ] + for adom in resp_obj[1]: + if adom["tab_status"] != "": + append_list.append(to_text(adom["name"])) + self._adom_list = append_list + return resp_obj + + def get_locked_adom_list(self): + """ + Gets the list of locked adoms + """ + try: + locked_list = list() + locked_by_user_list = list() + for adom in self._adom_list: + adom_lock_info = self.get_lock_info(adom=adom) + try: + if adom_lock_info[1]["status"]["message"] == "OK": + continue + except Exception: + pass + try: + if adom_lock_info[1][0]["lock_user"]: + locked_list.append(to_text(adom)) + if adom_lock_info[1][0]["lock_user"] == self._logged_in_user: + locked_by_user_list.append({"adom": to_text(adom), "user": to_text(adom_lock_info[1][0]["lock_user"])}) + except Exception as err: + raise FAZBaseException(err) + self._locked_adom_list = locked_list + self._locked_adoms_by_user = locked_by_user_list + + except Exception as err: + raise FAZBaseException(msg=("An error occurred while trying to get the locked adom list. Error: " + + to_text(err))) + + ################################# + # END DATABASE LOCK CONTEXT CODE + ################################# diff --git a/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py b/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py new file mode 100644 index 000000000..bbdaacb8d --- /dev/null +++ b/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py @@ -0,0 +1,459 @@ +# Copyright (c) 2018 Fortinet and/or its affiliates. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +name: fortimanager +short_description: HttpApi Plugin for Fortinet FortiManager Appliance or VM. +description: + - This HttpApi plugin provides methods to connect to Fortinet FortiManager Appliance or VM via JSON RPC API. +''' + +import json +from ansible.errors import AnsibleError +from ansible.plugins.httpapi import HttpApiBase +from ansible.module_utils.basic import to_text + +try: + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import BASE_HEADERS + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGBaseException + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRCommon + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRMethods + HAS_FORTIMANAGER_COLLECTION = True +except ImportError: + HAS_FORTIMANAGER_COLLECTION = False + + +class HttpApi(HttpApiBase): + def __init__(self, connection): + super(HttpApi, self).__init__(connection) + self._req_id = 0 + self._sid = None + self._url = "/jsonrpc" + self._host = None + self._tools = FMGRCommon + self._debug = False + self._connected_fmgr = None + self._last_response_msg = None + self._last_response_code = None + self._last_data_payload = None + self._last_url = None + self._last_response_raw = None + self._locked_adom_list = list() + self._locked_adoms_by_user = list() + self._uses_workspace = False + self._uses_adoms = False + self._adom_list = list() + self._logged_in_user = None + if not HAS_FORTIMANAGER_COLLECTION: + raise AnsibleError("The community.fortios.fortimanager httpapi plugin requires the fortios.fortimanager collection.") + + def set_become(self, become_context): + """ + ELEVATION IS NOT REQUIRED ON FORTINET DEVICES - SKIPPED. + :param become_context: Unused input. + :return: None + """ + return None + + def update_auth(self, response, response_data): + """ + TOKENS ARE NOT USED SO NO NEED TO UPDATE AUTH. + :param response: Unused input. + :param response_data Unused_input. + :return: None + """ + return None + + def login(self, username, password): + + """ + This function will log the plugin into FortiManager, and return the results. + :param username: Username of FortiManager Admin + :param password: Password of FortiManager Admin + + :return: Dictionary of status if it logged in or not. + """ + self._logged_in_user = username + self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, "sys/login/user", + passwd=password, user=username, )) + + if "FortiManager object connected to FortiManager" in self.__str__(): + # If Login worked, then inspect the FortiManager for Workspace Mode, and it's system information. + self.inspect_fmgr() + return + else: + raise FMGBaseException(msg="Unknown error while logging in...connection was lost during login operation...." + " Exiting") + + def inspect_fmgr(self): + # CHECK FOR WORKSPACE MODE TO SEE IF WE HAVE TO ENABLE ADOM LOCKS + status = self.get_system_status() + if status[0] == -11: + # THE CONNECTION GOT LOST SOMEHOW, REMOVE THE SID AND REPORT BAD LOGIN + self.logout() + raise FMGBaseException(msg="Error -11 -- the Session ID was likely malformed somehow. Contact authors." + " Exiting") + elif status[0] == 0: + try: + self.check_mode() + if self._uses_adoms: + self.get_adom_list() + if self._uses_workspace: + self.get_locked_adom_list() + self._connected_fmgr = status[1] + self._host = self._connected_fmgr["Hostname"] + except BaseException: + pass + return + + def logout(self): + """ + This function will logout of the FortiManager. + """ + if self.sid is not None: + # IF WE WERE USING WORKSPACES, THEN CLEAN UP OUR LOCKS IF THEY STILL EXIST + if self.uses_workspace: + self.get_lock_info() + self.run_unlock() + ret_code, response = self.send_request(FMGRMethods.EXEC, + self._tools.format_request(FMGRMethods.EXEC, "sys/logout")) + self.sid = None + return ret_code, response + + def send_request(self, method, params): + """ + Responsible for actual sending of data to the connection httpapi base plugin. Does some formatting too. + :param params: A formatted dictionary that was returned by self.common_datagram_params() + before being called here. + :param method: The preferred API Request method (GET, ADD, POST, etc....) + :type method: basestring + + :return: Dictionary of status, if it logged in or not. + """ + try: + if self.sid is None and params[0]["url"] != "sys/login/user": + try: + self.connection._connect() + except Exception as err: + raise FMGBaseException( + msg="An problem happened with the httpapi plugin self-init connection process. " + "Error: " + to_text(err)) + except IndexError: + raise FMGBaseException("An attempt was made at communicating with a FMG with " + "no valid session and an incorrectly formatted request.") + except Exception as err: + raise FMGBaseException("An attempt was made at communicating with a FMG with " + "no valid session and an unexpected error was discovered. \n Error: " + to_text(err)) + + self._update_request_id() + json_request = { + "method": method, + "params": params, + "session": self.sid, + "id": self.req_id, + "verbose": 1 + } + data = json.dumps(json_request, ensure_ascii=False).replace('\\\\', '\\') + try: + # Sending URL and Data in Unicode, per Ansible Specifications for Connection Plugins + response, response_data = self.connection.send(path=to_text(self._url), data=to_text(data), + headers=BASE_HEADERS) + # Get Unicode Response - Must convert from StringIO to unicode first so we can do a replace function below + result = json.loads(to_text(response_data.getvalue())) + self._update_self_from_response(result, self._url, data) + return self._handle_response(result) + except Exception as err: + raise FMGBaseException(err) + + def _handle_response(self, response): + self._set_sid(response) + if isinstance(response["result"], list): + result = response["result"][0] + else: + result = response["result"] + if "data" in result: + return result["status"]["code"], result["data"] + else: + return result["status"]["code"], result + + def _update_self_from_response(self, response, url, data): + self._last_response_raw = response + if isinstance(response["result"], list): + result = response["result"][0] + else: + result = response["result"] + if "status" in result: + self._last_response_code = result["status"]["code"] + self._last_response_msg = result["status"]["message"] + self._last_url = url + self._last_data_payload = data + + def _set_sid(self, response): + if self.sid is None and "session" in response: + self.sid = response["session"] + + def return_connected_fmgr(self): + """ + Returns the data stored under self._connected_fmgr + + :return: dict + """ + try: + if self._connected_fmgr: + return self._connected_fmgr + except Exception: + raise FMGBaseException("Couldn't Retrieve Connected FMGR Stats") + + def get_system_status(self): + """ + Returns the system status page from the FortiManager, for logging and other uses. + return: status + """ + status = self.send_request(FMGRMethods.GET, self._tools.format_request(FMGRMethods.GET, "sys/status")) + return status + + @property + def debug(self): + return self._debug + + @debug.setter + def debug(self, val): + self._debug = val + + @property + def req_id(self): + return self._req_id + + @req_id.setter + def req_id(self, val): + self._req_id = val + + def _update_request_id(self, reqid=0): + self.req_id = reqid if reqid != 0 else self.req_id + 1 + + @property + def sid(self): + return self._sid + + @sid.setter + def sid(self, val): + self._sid = val + + def __str__(self): + if self.sid is not None and self.connection._url is not None: + return "FortiManager object connected to FortiManager: " + to_text(self.connection._url) + return "FortiManager object with no valid connection to a FortiManager appliance." + + ################################## + # BEGIN DATABASE LOCK CONTEXT CODE + ################################## + + @property + def uses_workspace(self): + return self._uses_workspace + + @uses_workspace.setter + def uses_workspace(self, val): + self._uses_workspace = val + + @property + def uses_adoms(self): + return self._uses_adoms + + @uses_adoms.setter + def uses_adoms(self, val): + self._uses_adoms = val + + def add_adom_to_lock_list(self, adom): + if adom not in self._locked_adom_list: + self._locked_adom_list.append(adom) + + def remove_adom_from_lock_list(self, adom): + if adom in self._locked_adom_list: + self._locked_adom_list.remove(adom) + + def check_mode(self): + """ + Checks FortiManager for the use of Workspace mode + """ + url = "/cli/global/system/global" + code, resp_obj = self.send_request(FMGRMethods.GET, + self._tools.format_request(FMGRMethods.GET, + url, + fields=["workspace-mode", "adom-status"])) + try: + if resp_obj["workspace-mode"] == "workflow": + self.uses_workspace = True + elif resp_obj["workspace-mode"] == "disabled": + self.uses_workspace = False + except KeyError: + raise FMGBaseException(msg="Couldn't determine workspace-mode in the plugin") + try: + if resp_obj["adom-status"] in [1, "enable"]: + self.uses_adoms = True + else: + self.uses_adoms = False + except KeyError: + raise FMGBaseException(msg="Couldn't determine adom-status in the plugin") + + def run_unlock(self): + """ + Checks for ADOM status, if locked, it will unlock + """ + for adom_locked in self._locked_adoms_by_user: + adom = adom_locked["adom"] + self.unlock_adom(adom) + + def lock_adom(self, adom=None, *args, **kwargs): + """ + Locks an ADOM for changes + """ + if adom: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lock/" + else: + url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/lock" + code, respobj = self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url)) + if code == 0 and respobj["status"]["message"].lower() == "ok": + self.add_adom_to_lock_list(adom) + return code, respobj + + def unlock_adom(self, adom=None, *args, **kwargs): + """ + Unlocks an ADOM after changes + """ + if adom: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/unlock/" + else: + url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/unlock" + code, respobj = self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url)) + if code == 0 and respobj["status"]["message"].lower() == "ok": + self.remove_adom_from_lock_list(adom) + return code, respobj + + def commit_changes(self, adom=None, aux=False, *args, **kwargs): + """ + Commits changes to an ADOM + """ + if adom: + if aux: + url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom) + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/commit/" + else: + url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom) + else: + url = "/dvmdb/adom/root/workspace/commit" + return self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url)) + + def get_lock_info(self, adom=None): + """ + Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible + for some reason, then unlock it. + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/lockinfo" + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lockinfo/" + else: + url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom) + datagram = {} + data = self._tools.format_request(FMGRMethods.GET, url, **datagram) + resp_obj = self.send_request(FMGRMethods.GET, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. " + "Error: " + to_text(resp_obj))) + elif code == 0: + try: + if resp_obj[1]["status"]["message"] == "OK": + self._lock_info = None + except Exception: + self._lock_info = resp_obj[1] + return resp_obj + + def get_adom_list(self): + """ + Gets the list of ADOMs for the FortiManager + """ + if self.uses_adoms: + url = "/dvmdb/adom" + datagram = {} + data = self._tools.format_request(FMGRMethods.GET, url, **datagram) + resp_obj = self.send_request(FMGRMethods.GET, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to get the ADOM Info. " + "Error: " + to_text(resp_obj))) + elif code == 0: + num_of_adoms = len(resp_obj[1]) + append_list = ['root', ] + for adom in resp_obj[1]: + if adom["tab_status"] != "": + append_list.append(to_text(adom["name"])) + self._adom_list = append_list + return resp_obj + + def get_locked_adom_list(self): + """ + Gets the list of locked adoms + """ + try: + locked_list = list() + locked_by_user_list = list() + for adom in self._adom_list: + adom_lock_info = self.get_lock_info(adom=adom) + try: + if adom_lock_info[1]["status"]["message"] == "OK": + continue + except IndexError as err: + pass + try: + if adom_lock_info[1][0]["lock_user"]: + locked_list.append(to_text(adom)) + if adom_lock_info[1][0]["lock_user"] == self._logged_in_user: + locked_by_user_list.append({"adom": to_text(adom), + "user": to_text(adom_lock_info[1][0]["lock_user"])}) + except Exception as err: + raise FMGBaseException(err) + self._locked_adom_list = locked_list + self._locked_adoms_by_user = locked_by_user_list + + except Exception as err: + raise FMGBaseException(msg=("An error occurred while trying to get the locked adom list. Error: " + + to_text(err))) + + ################################ + # END DATABASE LOCK CONTEXT CODE + ################################ diff --git a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py new file mode 100644 index 000000000..50cd95cc6 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py @@ -0,0 +1,291 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# (c) 2017 Fortinet, Inc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +# BEGIN STATIC DATA AND MESSAGES +class FAZMethods: + GET = "get" + SET = "set" + EXEC = "exec" + EXECUTE = "exec" + UPDATE = "update" + ADD = "add" + DELETE = "delete" + REPLACE = "replace" + CLONE = "clone" + MOVE = "move" + + +BASE_HEADERS = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' +} + + +# FAZ RETURN CODES +FAZ_RC = { + "faz_return_codes": { + 0: { + "msg": "OK", + "changed": True, + "stop_on_success": True + }, + -100000: { + "msg": "Module returned without actually running anything. " + "Check parameters, and please contact the authors if needed.", + "failed": True + }, + -2: { + "msg": "Object already exists.", + "skipped": True, + "changed": False, + "good_codes": [0, -2] + }, + -6: { + "msg": "Invalid Url. Sometimes this can happen because the path is mapped to a hostname or object that" + " doesn't exist. Double check your input object parameters." + }, + -3: { + "msg": "Object doesn't exist.", + "skipped": True, + "changed": False, + "good_codes": [0, -3] + }, + -10131: { + "msg": "Object dependency failed. Do all named objects in parameters exist?", + "changed": False, + "skipped": True + }, + -9998: { + "msg": "Duplicate object. Try using mode='set', if using add. STOPPING. Use 'ignore_errors=yes' in playbook" + "to override and mark successful.", + }, + -20042: { + "msg": "Device Unreachable.", + "skipped": True + }, + -10033: { + "msg": "Duplicate object. Try using mode='set', if using add.", + "changed": False, + "skipped": True + }, + -10000: { + "msg": "Duplicate object. Try using mode='set', if using add.", + "changed": False, + "skipped": True + }, + -20010: { + "msg": "Device already added to FortiAnalyzer. Serial number already in use.", + "good_codes": [0, -20010], + "changed": False, + "stop_on_failure": False + }, + -20002: { + "msg": "Invalid Argument -- Does this Device exist on FortiAnalyzer?", + "changed": False, + "skipped": True, + } + } +} + +DEFAULT_RESULT_OBJ = (-100000, {"msg": "Nothing Happened. Check that handle_response is being called!"}) +FAIL_SOCKET_MSG = {"msg": "Socket Path Empty! The persistent connection manager is messed up. " + "Try again in a few moments."} + + +# BEGIN ERROR EXCEPTIONS +class FAZBaseException(Exception): + """Wrapper to catch the unexpected""" + + def __init__(self, msg=None, *args, **kwargs): + if msg is None: + msg = "An exception occurred within the fortianalyzer.py httpapi connection plugin." + super(FAZBaseException, self).__init__(msg, *args) + +# END ERROR CLASSES + + +# BEGIN CLASSES +class FAZCommon(object): + + @staticmethod + def format_request(method, url, *args, **kwargs): + """ + Formats the payload from the module, into a payload the API handler can use. + + :param url: Connection URL to access + :type url: string + :param method: The preferred API Request method (GET, ADD, POST, etc....) + :type method: basestring + :param kwargs: The payload dictionary from the module to be converted. + + :return: Properly formatted dictionary payload for API Request via Connection Plugin. + :rtype: dict + """ + + params = [{"url": url}] + if args: + for arg in args: + params[0].update(arg) + if kwargs: + keylist = list(kwargs) + for k in keylist: + kwargs[k.replace("__", "-")] = kwargs.pop(k) + if method == "get" or method == "clone": + params[0].update(kwargs) + else: + if kwargs.get("data", False): + params[0]["data"] = kwargs["data"] + else: + params[0]["data"] = kwargs + return params + + @staticmethod + def split_comma_strings_into_lists(obj): + """ + Splits a CSV String into a list. Also takes a dictionary, and converts any CSV strings in any key, to a list. + + :param obj: object in CSV format to be parsed. + :type obj: str or dict + + :return: A list containing the CSV items. + :rtype: list + """ + return_obj = () + if isinstance(obj, dict): + if len(obj) > 0: + for k, v in obj.items(): + if isinstance(v, str): + new_list = list() + if "," in v: + new_items = v.split(",") + for item in new_items: + new_list.append(item.strip()) + obj[k] = new_list + return_obj = obj + elif isinstance(obj, str): + return_obj = obj.replace(" ", "").split(",") + + return return_obj + + @staticmethod + def cidr_to_netmask(cidr): + """ + Converts a CIDR Network string to full blown IP/Subnet format in decimal format. + Decided not use IP Address module to keep includes to a minimum. + + :param cidr: String object in CIDR format to be processed + :type cidr: str + + :return: A string object that looks like this "x.x.x.x/y.y.y.y" + :rtype: str + """ + if isinstance(cidr, str): + cidr = int(cidr) + mask = (0xffffffff >> (32 - cidr)) << (32 - cidr) + return (str((0xff000000 & mask) >> 24) + '.' + + str((0x00ff0000 & mask) >> 16) + '.' + + str((0x0000ff00 & mask) >> 8) + '.' + + str((0x000000ff & mask))) + + @staticmethod + def paramgram_child_list_override(list_overrides, paramgram, module): + """ + If a list of items was provided to a "parent" paramgram attribute, the paramgram needs to be rewritten. + The child keys of the desired attribute need to be deleted, and then that "parent" keys' contents is replaced + With the list of items that was provided. + + :param list_overrides: Contains the response from the FortiAnalyzer. + :type list_overrides: list + :param paramgram: Contains the paramgram passed to the modules' local modify function. + :type paramgram: dict + :param module: Contains the Ansible Module Object being used by the module. + :type module: classObject + + :return: A new "paramgram" refactored to allow for multiple entries being added. + :rtype: dict + """ + if len(list_overrides) > 0: + for list_variable in list_overrides: + try: + list_variable = list_variable.replace("-", "_") + override_data = module.params[list_variable] + if override_data: + del paramgram[list_variable] + paramgram[list_variable] = override_data + except BaseException as e: + raise FAZBaseException("Error occurred merging custom lists for the paramgram parent: " + str(e)) + return paramgram + + @staticmethod + def syslog(module, msg): + try: + module.log(msg=msg) + except BaseException: + pass + + +# RECURSIVE FUNCTIONS START +def prepare_dict(obj): + """ + Removes any keys from a dictionary that are only specific to our use in the module. FortiAnalyzer will reject + requests with these empty/None keys in it. + + :param obj: Dictionary object to be processed. + :type obj: dict + + :return: Processed dictionary. + :rtype: dict + """ + + list_of_elems = ["mode", "adom", "host", "username", "password"] + + if isinstance(obj, dict): + obj = dict((key, prepare_dict(value)) for (key, value) in obj.items() if key not in list_of_elems) + return obj + + +def scrub_dict(obj): + """ + Removes any keys from a dictionary that are EMPTY -- this includes parent keys. FortiAnalyzer doesn't + like empty keys in dictionaries + + :param obj: Dictionary object to be processed. + :type obj: dict + + :return: Processed dictionary. + :rtype: dict + """ + + if isinstance(obj, dict): + return dict((k, scrub_dict(v)) for k, v in obj.items() if v and scrub_dict(v)) + else: + return obj diff --git a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py new file mode 100644 index 000000000..74e85e30c --- /dev/null +++ b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py @@ -0,0 +1,476 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# (c) 2017 Fortinet, Inc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZ_RC +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import scrub_dict +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods + + +# ACTIVE BUG WITH OUR DEBUG IMPORT CALL - BECAUSE IT'S UNDER MODULE_UTILITIES +# WHEN module_common.recursive_finder() runs under the module loader, it looks for this namespace debug import +# and because it's not there, it always fails, regardless of it being under a try/catch here. +# we're going to move it to a different namespace. +# # check for debug lib +# try: +# from ansible.module_utils.fortianalyzer.fortianalyzer_debug import debug_dump +# HAS_FAZ_DEBUG = True +# except: +# HAS_FAZ_DEBUG = False + + +# BEGIN HANDLER CLASSES +class FortiAnalyzerHandler(object): + def __init__(self, conn, module): + self._conn = conn + self._module = module + self._tools = FAZCommon + self._uses_workspace = None + self._uses_adoms = None + self._locked_adom_list = list() + self._lock_info = None + + self.workspace_check() + if self._uses_workspace: + self.get_lock_info(adom=self._module.paramgram["adom"]) + + def process_request(self, url, datagram, method): + """ + Formats and Runs the API Request via Connection Plugin. Streamlined for use from Modules. + + :param url: Connection URL to access + :type url: string + :param datagram: The prepared payload for the API Request in dictionary format + :type datagram: dict + :param method: The preferred API Request method (GET, ADD, POST, etc....) + :type method: basestring + + :return: Dictionary containing results of the API Request via Connection Plugin. + :rtype: dict + """ + try: + adom = self._module.paramgram["adom"] + if self.uses_workspace and adom not in self._locked_adom_list and method != FAZMethods.GET: + self.lock_adom(adom=adom) + except BaseException as err: + raise FAZBaseException(err) + + data = self._tools.format_request(method, url, **datagram) + response = self._conn.send_request(method, data) + + try: + adom = self._module.paramgram["adom"] + if self.uses_workspace and adom in self._locked_adom_list \ + and response[0] == 0 and method != FAZMethods.GET: + self.commit_changes(adom=adom) + except BaseException as err: + raise FAZBaseException(err) + + # if HAS_FAZ_DEBUG: + # try: + # debug_dump(response, datagram, self._module.paramgram, url, method) + # except BaseException: + # pass + + return response + + def workspace_check(self): + """ + Checks FortiAnalyzer for the use of Workspace mode. + """ + url = "/cli/global/system/global" + data = {"fields": ["workspace-mode", "adom-status"]} + resp_obj = self.process_request(url, data, FAZMethods.GET) + try: + if resp_obj[1]["workspace-mode"] in ["workflow", "normal"]: + self.uses_workspace = True + elif resp_obj[1]["workspace-mode"] == "disabled": + self.uses_workspace = False + except KeyError: + self.uses_workspace = False + except BaseException as err: + raise FAZBaseException(msg="Couldn't determine workspace-mode in the plugin. Error: " + str(err)) + try: + if resp_obj[1]["adom-status"] in [1, "enable"]: + self.uses_adoms = True + else: + self.uses_adoms = False + except KeyError: + self.uses_adoms = False + except BaseException as err: + raise FAZBaseException(msg="Couldn't determine adom-status in the plugin. Error: " + str(err)) + + def run_unlock(self): + """ + Checks for ADOM status, if locked, it will unlock + """ + for adom_locked in self._locked_adom_list: + self.unlock_adom(adom_locked) + + def lock_adom(self, adom=None): + """ + Locks an ADOM for changes + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/lock" + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lock/" + else: + url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom) + datagram = {} + data = self._tools.format_request(FAZMethods.EXEC, url, **datagram) + resp_obj = self._conn.send_request(FAZMethods.EXEC, data) + code = resp_obj[0] + if code == 0 and resp_obj[1]["status"]["message"].lower() == "ok": + self.add_adom_to_lock_list(adom) + else: + lockinfo = self.get_lock_info(adom=adom) + self._module.fail_json(msg=("An error occurred trying to lock the adom. Error: " + + str(resp_obj) + ", LOCK INFO: " + str(lockinfo))) + return resp_obj + + def unlock_adom(self, adom=None): + """ + Unlocks an ADOM after changes + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/unlock" + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/unlock/" + else: + url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom) + datagram = {} + data = self._tools.format_request(FAZMethods.EXEC, url, **datagram) + resp_obj = self._conn.send_request(FAZMethods.EXEC, data) + code = resp_obj[0] + if code == 0 and resp_obj[1]["status"]["message"].lower() == "ok": + self.remove_adom_from_lock_list(adom) + else: + self._module.fail_json(msg=("An error occurred trying to unlock the adom. Error: " + str(resp_obj))) + return resp_obj + + def get_lock_info(self, adom=None): + """ + Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible + for some reason, then unlock it. + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/lockinfo" + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/lockinfo/" + else: + url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom) + datagram = {} + data = self._tools.format_request(FAZMethods.GET, url, **datagram) + resp_obj = self._conn.send_request(FAZMethods.GET, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. Error: " + str(resp_obj))) + elif code == 0: + self._lock_info = resp_obj[1] + return resp_obj + + def commit_changes(self, adom=None, aux=False): + """ + Commits changes to an ADOM + """ + if not adom or adom == "root": + url = "/dvmdb/adom/root/workspace/commit" + else: + if aux: + url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom) + else: + if adom.lower() == "global": + url = "/dvmdb/global/workspace/commit/" + else: + url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom) + datagram = {} + data = self._tools.format_request(FAZMethods.EXEC, url, **datagram) + resp_obj = self._conn.send_request(FAZMethods.EXEC, data) + code = resp_obj[0] + if code != 0: + self._module.fail_json(msg=("An error occurred trying to commit changes to the adom. Error: " + + str(resp_obj))) + + def govern_response(self, module, results, msg=None, good_codes=None, + stop_on_fail=None, stop_on_success=None, skipped=None, + changed=None, unreachable=None, failed=None, success=None, changed_if_success=None, + ansible_facts=None): + """ + This function will attempt to apply default values to canned responses from FortiAnalyzer we know of. + This saves time, and turns the response in the module into a "one-liner", while still giving us... + the flexibility to directly use return_response in modules if we have too. This function saves repeated code. + + :param module: The Ansible Module CLASS object, used to run fail/exit json + :type module: object + :param msg: An overridable custom message from the module that called this. + :type msg: string + :param results: A dictionary object containing an API call results + :type results: dict + :param good_codes: A list of exit codes considered successful from FortiAnalyzer + :type good_codes: list + :param stop_on_fail: If true, stops playbook run when return code is NOT IN good codes (default: true) + :type stop_on_fail: boolean + :param stop_on_success: If true, stops playbook run when return code is IN good codes (default: false) + :type stop_on_success: boolean + :param changed: If True, tells Ansible that object was changed (default: false) + :type skipped: boolean + :param skipped: If True, tells Ansible that object was skipped (default: false) + :type skipped: boolean + :param unreachable: If True, tells Ansible that object was unreachable (default: false) + :type unreachable: boolean + :param failed: If True, tells Ansible that execution was a failure. Overrides good_codes. (default: false) + :type unreachable: boolean + :param success: If True, tells Ansible that execution was a success. Overrides good_codes. (default: false) + :type unreachable: boolean + :param changed_if_success: If True, defaults to changed if successful if you specify or not" + :type changed_if_success: boolean + :param ansible_facts: A prepared dictionary of ansible facts from the execution. + :type ansible_facts: dict + """ + if module is None and results is None: + raise FAZBaseException("govern_response() was called without a module and/or results tuple! Fix!") + # Get the Return code from results + try: + rc = results[0] + except BaseException: + raise FAZBaseException("govern_response() was called without the return code at results[0]") + + # init a few items + rc_data = None + + # Get the default values for the said return code. + try: + rc_codes = FAZ_RC.get('faz_return_codes') + rc_data = rc_codes.get(rc) + except BaseException: + pass + + if not rc_data: + rc_data = {} + # ONLY add to overrides if not none -- This is very important that the keys aren't added at this stage + # if they are empty. And there aren't that many, so let's just do a few if then statements. + if good_codes is not None: + rc_data["good_codes"] = good_codes + if stop_on_fail is not None: + rc_data["stop_on_fail"] = stop_on_fail + if stop_on_success is not None: + rc_data["stop_on_success"] = stop_on_success + if skipped is not None: + rc_data["skipped"] = skipped + if changed is not None: + rc_data["changed"] = changed + if unreachable is not None: + rc_data["unreachable"] = unreachable + if failed is not None: + rc_data["failed"] = failed + if success is not None: + rc_data["success"] = success + if changed_if_success is not None: + rc_data["changed_if_success"] = changed_if_success + if results is not None: + rc_data["results"] = results + if msg is not None: + rc_data["msg"] = msg + if ansible_facts is None: + rc_data["ansible_facts"] = {} + else: + rc_data["ansible_facts"] = ansible_facts + + return self.return_response(module=module, + results=results, + msg=rc_data.get("msg", "NULL"), + good_codes=rc_data.get("good_codes", (0,)), + stop_on_fail=rc_data.get("stop_on_fail", True), + stop_on_success=rc_data.get("stop_on_success", False), + skipped=rc_data.get("skipped", False), + changed=rc_data.get("changed", False), + changed_if_success=rc_data.get("changed_if_success", False), + unreachable=rc_data.get("unreachable", False), + failed=rc_data.get("failed", False), + success=rc_data.get("success", False), + ansible_facts=rc_data.get("ansible_facts", dict())) + + def return_response(self, module, results, msg="NULL", good_codes=(0,), + stop_on_fail=True, stop_on_success=False, skipped=False, + changed=False, unreachable=False, failed=False, success=False, changed_if_success=True, + ansible_facts=()): + """ + This function controls the logout and error reporting after an method or function runs. The exit_json for + ansible comes from logic within this function. If this function returns just the msg, it means to continue + execution on the playbook. It is called from the ansible module, or from the self.govern_response function. + + :param module: The Ansible Module CLASS object, used to run fail/exit json + :type module: object + :param msg: An overridable custom message from the module that called this. + :type msg: string + :param results: A dictionary object containing an API call results + :type results: dict + :param good_codes: A list of exit codes considered successful from FortiAnalyzer + :type good_codes: list + :param stop_on_fail: If true, stops playbook run when return code is NOT IN good codes (default: true) + :type stop_on_fail: boolean + :param stop_on_success: If true, stops playbook run when return code is IN good codes (default: false) + :type stop_on_success: boolean + :param changed: If True, tells Ansible that object was changed (default: false) + :type skipped: boolean + :param skipped: If True, tells Ansible that object was skipped (default: false) + :type skipped: boolean + :param unreachable: If True, tells Ansible that object was unreachable (default: false) + :type unreachable: boolean + :param failed: If True, tells Ansible that execution was a failure. Overrides good_codes. (default: false) + :type unreachable: boolean + :param success: If True, tells Ansible that execution was a success. Overrides good_codes. (default: false) + :type unreachable: boolean + :param changed_if_success: If True, defaults to changed if successful if you specify or not" + :type changed_if_success: boolean + :param ansible_facts: A prepared dictionary of ansible facts from the execution. + :type ansible_facts: dict + + :return: A string object that contains an error message + :rtype: str + """ + + # VALIDATION ERROR + if (len(results) == 0) or (failed and success) or (changed and unreachable): + module.exit_json(msg="Handle_response was called with no results, or conflicting failed/success or " + "changed/unreachable parameters. Fix the exit code on module. " + "Generic Failure", failed=True) + + # IDENTIFY SUCCESS/FAIL IF NOT DEFINED + if not failed and not success: + if len(results) > 0: + if results[0] not in good_codes: + failed = True + elif results[0] in good_codes: + success = True + + if len(results) > 0: + # IF NO MESSAGE WAS SUPPLIED, GET IT FROM THE RESULTS, IF THAT DOESN'T WORK, THEN WRITE AN ERROR MESSAGE + if msg == "NULL": + try: + msg = results[1]['status']['message'] + except BaseException: + msg = "No status message returned at results[1][status][message], " \ + "and none supplied to msg parameter for handle_response." + + if failed: + # BECAUSE SKIPPED/FAILED WILL OFTEN OCCUR ON CODES THAT DON'T GET INCLUDED, THEY ARE CONSIDERED FAILURES + # HOWEVER, THEY ARE MUTUALLY EXCLUSIVE, SO IF IT IS MARKED SKIPPED OR UNREACHABLE BY THE MODULE LOGIC + # THEN REMOVE THE FAILED FLAG SO IT DOESN'T OVERRIDE THE DESIRED STATUS OF SKIPPED OR UNREACHABLE. + if failed and skipped: + failed = False + if failed and unreachable: + failed = False + if stop_on_fail: + if self._uses_workspace: + try: + self.run_unlock() + except BaseException as err: + raise FAZBaseException(msg=("Couldn't unlock ADOM! Error: " + str(err))) + module.exit_json(msg=msg, failed=failed, changed=changed, unreachable=unreachable, skipped=skipped, + results=results[1], ansible_facts=ansible_facts, rc=results[0], + invocation={"module_args": ansible_facts["ansible_params"]}) + elif success: + if changed_if_success: + changed = True + success = False + if stop_on_success: + if self._uses_workspace: + try: + self.run_unlock() + except BaseException as err: + raise FAZBaseException(msg=("Couldn't unlock ADOM! Error: " + str(err))) + module.exit_json(msg=msg, success=success, changed=changed, unreachable=unreachable, + skipped=skipped, results=results[1], ansible_facts=ansible_facts, rc=results[0], + invocation={"module_args": ansible_facts["ansible_params"]}) + return msg + + @staticmethod + def construct_ansible_facts(response, ansible_params, paramgram, *args, **kwargs): + """ + Constructs a dictionary to return to ansible facts, containing various information about the execution. + + :param response: Contains the response from the FortiAnalyzer. + :type response: dict + :param ansible_params: Contains the parameters Ansible was called with. + :type ansible_params: dict + :param paramgram: Contains the paramgram passed to the modules' local modify function. + :type paramgram: dict + :param args: Free-form arguments that could be added. + :param kwargs: Free-form keyword arguments that could be added. + + :return: A dictionary containing lots of information to append to Ansible Facts. + :rtype: dict + """ + + facts = { + "response": response, + "ansible_params": scrub_dict(ansible_params), + "paramgram": scrub_dict(paramgram), + } + + if args: + facts["custom_args"] = args + if kwargs: + facts.update(kwargs) + + return facts + + @property + def uses_workspace(self): + return self._uses_workspace + + @uses_workspace.setter + def uses_workspace(self, val): + self._uses_workspace = val + + @property + def uses_adoms(self): + return self._uses_adoms + + @uses_adoms.setter + def uses_adoms(self, val): + self._uses_adoms = val + + def add_adom_to_lock_list(self, adom): + if adom not in self._locked_adom_list: + self._locked_adom_list.append(adom) + + def remove_adom_from_lock_list(self, adom): + if adom in self._locked_adom_list: + self._locked_adom_list.remove(adom) diff --git a/ansible_collections/community/fortios/plugins/modules/faz_device.py b/ansible_collections/community/fortios/plugins/modules/faz_device.py new file mode 100644 index 000000000..07a695575 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/faz_device.py @@ -0,0 +1,432 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: faz_device +author: Luke Weighall (@lweighall) +short_description: Add or remove device +description: + - Add or remove a device or list of devices to FortiAnalyzer Device Manager. ADOM Capable. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: true + default: root + type: str + + mode: + description: + - Add or delete devices. Or promote unregistered devices that are in the FortiAnalyzer "waiting pool" + required: false + default: add + choices: ["add", "delete", "promote"] + type: str + + device_username: + description: + - The username of the device being added to FortiAnalyzer. + required: false + type: str + + device_password: + description: + - The password of the device being added to FortiAnalyzer. + required: false + type: str + + device_ip: + description: + - The IP of the device being added to FortiAnalyzer. + required: false + type: str + + device_unique_name: + description: + - The desired "friendly" name of the device being added to FortiAnalyzer. + required: false + type: str + + device_serial: + description: + - The serial number of the device being added to FortiAnalyzer. + required: false + type: str + + os_type: + description: + - The os type of the device being added (default 0). + required: true + choices: ["unknown", "fos", "fsw", "foc", "fml", "faz", "fwb", "fch", "fct", "log", "fmg", "fsa", "fdd", "fac"] + type: str + + mgmt_mode: + description: + - Management Mode of the device you are adding. + choices: ["unreg", "fmg", "faz", "fmgfaz"] + required: true + type: str + + os_minor_vers: + description: + - Minor OS rev of the device. + required: true + type: str + + os_ver: + description: + - Major OS rev of the device + required: true + choices: ["unknown", "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0"] + type: str + + platform_str: + description: + - Required for determine the platform for VM platforms. ie FortiGate-VM64 + required: false + type: str + + faz_quota: + description: + - Specifies the quota for the device in FAZ + required: False + type: str +''' + +EXAMPLES = ''' +- name: DISCOVER AND ADD DEVICE A PHYSICAL FORTIGATE + community.fortios.faz_device: + adom: "root" + device_username: "admin" + device_password: "admin" + device_ip: "10.10.24.201" + device_unique_name: "FGT1" + device_serial: "FGVM000000117994" + state: "present" + mgmt_mode: "faz" + os_type: "fos" + os_ver: "5.0" + minor_rev: 6 + + +- name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE + community.fortios.faz_device: + adom: "root" + device_username: "admin" + device_password: "admin" + device_ip: "10.10.24.202" + device_unique_name: "FGT2" + mgmt_mode: "faz" + os_type: "fos" + os_ver: "5.0" + minor_rev: 6 + state: "present" + platform_str: "FortiGate-VM64" + +- name: DELETE DEVICE FGT01 + community.fortios.faz_device: + adom: "root" + device_unique_name: "ansible-fgt01" + mode: "delete" + +- name: DELETE DEVICE FGT02 + community.fortios.faz_device: + adom: "root" + device_unique_name: "ansible-fgt02" + mode: "delete" + +- name: PROMOTE FGT01 IN FAZ BY IP + community.fortios.faz_device: + adom: "root" + device_password: "fortinet" + device_ip: "10.7.220.151" + device_username: "ansible" + mgmt_mode: "faz" + mode: "promote" + + +- name: PROMOTE FGT02 IN FAZ + community.fortios.faz_device: + adom: "root" + device_password: "fortinet" + device_unique_name: "ansible-fgt02" + device_username: "ansible" + mgmt_mode: "faz" + mode: "promote" + +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.fortianalyzer import FortiAnalyzerHandler +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import DEFAULT_RESULT_OBJ +from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAIL_SOCKET_MSG + + +def faz_add_device(faz, paramgram): + """ + This method is used to add devices to the faz or delete them + """ + + datagram = { + "adom": paramgram["adom"], + "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"], + "ip": paramgram["ip"], "name": paramgram["device_unique_name"], + "mgmt_mode": paramgram["mgmt_mode"], "os_type": paramgram["os_type"], + "mr": paramgram["os_minor_vers"]} + } + + if paramgram["platform_str"] is not None: + datagram["device"]["platform_str"] = paramgram["platform_str"] + + if paramgram["sn"] is not None: + datagram["device"]["sn"] = paramgram["sn"] + + if paramgram["device_action"] is not None: + datagram["device"]["device_action"] = paramgram["device_action"] + + if paramgram["faz.quota"] is not None: + datagram["device"]["faz.quota"] = paramgram["faz.quota"] + + url = '/dvm/cmd/add/device/' + response = faz.process_request(url, datagram, FAZMethods.EXEC) + return response + + +def faz_delete_device(faz, paramgram): + """ + This method deletes a device from the FAZ + """ + datagram = { + "adom": paramgram["adom"], + "device": paramgram["device_unique_name"], + } + + url = '/dvm/cmd/del/device/' + response = faz.process_request(url, datagram, FAZMethods.EXEC) + return response + + +def faz_get_unknown_devices(faz): + """ + This method gets devices with an unknown management type field + """ + + faz_filter = ["mgmt_mode", "==", "0"] + + datagram = { + "filter": faz_filter + } + + url = "/dvmdb/device" + response = faz.process_request(url, datagram, FAZMethods.GET) + + return response + + +def faz_approve_unregistered_device_by_ip(faz, paramgram): + """ + This method approves unregistered devices by ip. + """ + # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE + unknown_devices = faz_get_unknown_devices(faz) + target_device = None + if unknown_devices[0] == 0: + for device in unknown_devices[1]: + if device["ip"] == paramgram["ip"]: + target_device = device + else: + return "No devices are waiting to be registered!" + + # now that we have the target device details...fill out the datagram and make the call to promote it + if target_device is not None: + target_device_paramgram = { + "adom": paramgram["adom"], + "ip": target_device["ip"], + "device_username": paramgram["device_username"], + "device_password": paramgram["device_password"], + "device_unique_name": paramgram["device_unique_name"], + "sn": target_device["sn"], + "os_type": target_device["os_type"], + "mgmt_mode": paramgram["mgmt_mode"], + "os_minor_vers": target_device["mr"], + "os_ver": target_device["os_ver"], + "platform_str": target_device["platform_str"], + "faz.quota": target_device["faz.quota"], + "device_action": paramgram["device_action"] + } + + add_device = faz_add_device(faz, target_device_paramgram) + return add_device + + return str("Couldn't find the desired device with ip: " + str(paramgram["device_ip"])) + + +def faz_approve_unregistered_device_by_name(faz, paramgram): + # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE + unknown_devices = faz_get_unknown_devices(faz) + target_device = None + if unknown_devices[0] == 0: + for device in unknown_devices[1]: + if device["name"] == paramgram["device_unique_name"]: + target_device = device + else: + return "No devices are waiting to be registered!" + + # now that we have the target device details...fill out the datagram and make the call to promote it + if target_device is not None: + target_device_paramgram = { + "adom": paramgram["adom"], + "ip": target_device["ip"], + "device_username": paramgram["device_username"], + "device_password": paramgram["device_password"], + "device_unique_name": paramgram["device_unique_name"], + "sn": target_device["sn"], + "os_type": target_device["os_type"], + "mgmt_mode": paramgram["mgmt_mode"], + "os_minor_vers": target_device["mr"], + "os_ver": target_device["os_ver"], + "platform_str": target_device["platform_str"], + "faz.quota": target_device["faz.quota"], + "device_action": paramgram["device_action"] + } + + add_device = faz_add_device(faz, target_device_paramgram) + return add_device + + return str("Couldn't find the desired device with name: " + str(paramgram["device_unique_name"])) + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "delete", "promote"], type="str", default="add"), + + device_ip=dict(required=False, type="str"), + device_username=dict(required=False, type="str"), + device_password=dict(required=False, type="str", no_log=True), + device_unique_name=dict(required=False, type="str"), + device_serial=dict(required=False, type="str"), + + os_type=dict(required=False, type="str", choices=["unknown", "fos", "fsw", "foc", "fml", + "faz", "fwb", "fch", "fct", "log", "fmg", + "fsa", "fdd", "fac"]), + mgmt_mode=dict(required=False, type="str", choices=["unreg", "fmg", "faz", "fmgfaz"]), + os_minor_vers=dict(required=False, type="str"), + os_ver=dict(required=False, type="str", choices=["unknown", "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0"]), + platform_str=dict(required=False, type="str"), + faz_quota=dict(required=False, type="str") + ) + + required_if = [ + ['mode', 'delete', ['device_unique_name']], + ['mode', 'add', ['device_serial', 'device_username', + 'device_password', 'device_unique_name', 'device_ip', 'mgmt_mode', 'platform_str']] + + ] + + module = AnsibleModule(argument_spec, supports_check_mode=True, required_if=required_if, ) + + # START SESSION LOGIC + paramgram = { + "adom": module.params["adom"], + "mode": module.params["mode"], + "ip": module.params["device_ip"], + "device_username": module.params["device_username"], + "device_password": module.params["device_password"], + "device_unique_name": module.params["device_unique_name"], + "sn": module.params["device_serial"], + "os_type": module.params["os_type"], + "mgmt_mode": module.params["mgmt_mode"], + "os_minor_vers": module.params["os_minor_vers"], + "os_ver": module.params["os_ver"], + "platform_str": module.params["platform_str"], + "faz.quota": module.params["faz_quota"], + "device_action": None + } + # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO + + if paramgram["mode"] == "add": + paramgram["device_action"] = "add_model" + elif paramgram["mode"] == "promote": + paramgram["device_action"] = "promote_unreg" + module.paramgram = paramgram + + # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS + faz = None + if module._socket_path: + connection = Connection(module._socket_path) + faz = FortiAnalyzerHandler(connection, module) + faz.tools = FAZCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + + try: + if paramgram["mode"] == "add": + results = faz_add_device(faz, paramgram) + except BaseException as err: + raise FAZBaseException(msg="An error occurred trying to add the device. Error: " + str(err)) + + try: + if paramgram["mode"] == "promote": + if paramgram["ip"] is not None: + results = faz_approve_unregistered_device_by_ip(faz, paramgram) + elif paramgram["device_unique_name"] is not None: + results = faz_approve_unregistered_device_by_name(faz, paramgram) + except BaseException as err: + raise FAZBaseException(msg="An error occurred trying to promote the device. Error: " + str(err)) + + try: + if paramgram["mode"] == "delete": + results = faz_delete_device(faz, paramgram) + except BaseException as err: + raise FAZBaseException(msg="An error occurred trying to delete the device. Error: " + str(err)) + + # PROCESS RESULTS + try: + faz.govern_response(module=module, results=results, + ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram)) + except BaseException as err: + raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err)) + + # This should only be hit if faz.govern_response is missed or failed somehow. In fact. It should never be hit. + # But it's here JIC. + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device.py new file mode 100644 index 000000000..8f0c6045f --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_device.py @@ -0,0 +1,296 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_device +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Add or remove device from FortiManager. +description: + - Add or remove a device or list of devices from FortiManager Device Manager using JSON RPC API. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: true + default: root + + mode: + description: + - The desired mode of the specified object. + required: false + default: add + choices: ["add", "delete"] + + blind_add: + description: + - When adding a device, module will check if it exists, and skip if it does. + - If enabled, this option will stop the module from checking if it already exists, and blindly add the device. + required: false + default: "disable" + choices: ["enable", "disable"] + + device_username: + description: + - The username of the device being added to FortiManager. + required: false + + device_password: + description: + - The password of the device being added to FortiManager. + required: false + + device_ip: + description: + - The IP of the device being added to FortiManager. Supports both IPv4 and IPv6. + required: false + + device_unique_name: + description: + - The desired "friendly" name of the device being added to FortiManager. + required: false + + device_serial: + description: + - The serial number of the device being added to FortiManager. + required: false +''' + +EXAMPLES = ''' +- name: DISCOVER AND ADD DEVICE FGT1 + community.fortios.fmgr_device: + adom: "root" + device_username: "admin" + device_password: "admin" + device_ip: "10.10.24.201" + device_unique_name: "FGT1" + device_serial: "FGVM000000117994" + mode: "add" + blind_add: "enable" + +- name: DISCOVER AND ADD DEVICE FGT2 + community.fortios.fmgr_device: + adom: "root" + device_username: "admin" + device_password: "admin" + device_ip: "10.10.24.202" + device_unique_name: "FGT2" + device_serial: "FGVM000000117992" + mode: "delete" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def discover_device(fmgr, paramgram): + """ + This method is used to discover devices before adding them to FMGR + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + "odd_request_form": "True", + "device": {"adm_usr": paramgram["device_username"], + "adm_pass": paramgram["device_password"], + "ip": paramgram["device_ip"]} + } + + url = '/dvm/cmd/discover/device/' + + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def add_device(fmgr, paramgram): + """ + This method is used to add devices to the FMGR + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + "adom": paramgram["adom"], + "flags": ["create_task", "nonblocking"], + "odd_request_form": "True", + "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"], + "ip": paramgram["device_ip"], "name": paramgram["device_unique_name"], + "sn": paramgram["device_serial"], "mgmt_mode": "fmgfaz", "flags": 24} + } + + url = '/dvm/cmd/add/device/' + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def delete_device(fmgr, paramgram): + """ + This method deletes a device from the FMGR + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + datagram = { + "adom": paramgram["adom"], + "flags": ["create_task", "nonblocking"], + "device": paramgram["device_unique_name"], + } + + url = '/dvm/cmd/del/device/' + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def get_device(fmgr, paramgram): + """ + This method attempts to find the firewall on FortiManager to see if it already exists. + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + datagram = { + "adom": paramgram["adom"], + "filter": ["name", "==", paramgram["device_unique_name"]], + } + + url = '/dvmdb/adom/{adom}/device/{name}'.format(adom=paramgram["adom"], + name=paramgram["device_unique_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "delete"], type="str", default="add"), + blind_add=dict(choices=["enable", "disable"], type="str", default="disable"), + device_ip=dict(required=False, type="str"), + device_username=dict(required=False, type="str"), + device_password=dict(required=False, type="str", no_log=True), + device_unique_name=dict(required=True, type="str"), + device_serial=dict(required=False, type="str") + ) + + # BUILD MODULE OBJECT SO WE CAN BUILD THE PARAMGRAM + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + + # BUILD THE PARAMGRAM + paramgram = { + "device_ip": module.params["device_ip"], + "device_username": module.params["device_username"], + "device_password": module.params["device_password"], + "device_unique_name": module.params["device_unique_name"], + "device_serial": module.params["device_serial"], + "adom": module.params["adom"], + "mode": module.params["mode"] + } + + # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO + module.paramgram = paramgram + + # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + try: + if paramgram["mode"] == "add": + # CHECK IF DEVICE EXISTS + if module.params["blind_add"] == "disable": + exists_results = get_device(fmgr, paramgram) + fmgr.govern_response(module=module, results=exists_results, good_codes=(0, -3), changed=False, + ansible_facts=fmgr.construct_ansible_facts(exists_results, + module.params, paramgram)) + + discover_results = discover_device(fmgr, paramgram) + fmgr.govern_response(module=module, results=discover_results, stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(discover_results, + module.params, paramgram)) + + if discover_results[0] == 0: + results = add_device(fmgr, paramgram) + fmgr.govern_response(module=module, results=discover_results, stop_on_success=True, + changed_if_success=True, + ansible_facts=fmgr.construct_ansible_facts(discover_results, + module.params, paramgram)) + + if paramgram["mode"] == "delete": + results = delete_device(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py new file mode 100644 index 000000000..e36dad95f --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_device_config +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Edit device configurations +description: + - Edit device configurations from FortiManager Device Manager using JSON RPC API. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + device_unique_name: + description: + - The unique device's name that you are editing. A.K.A. Friendly name of the device in FortiManager. + required: True + + device_hostname: + description: + - The device's new hostname. + required: false + + install_config: + description: + - Tells FMGR to attempt to install the config after making it. + required: false + default: disable + + interface: + description: + - The interface/port number you are editing. + required: false + + interface_ip: + description: + - The IP and subnet of the interface/port you are editing. + required: false + + interface_allow_access: + description: + - Specify what protocols are allowed on the interface, comma-separated list (see examples). + required: false +''' + +EXAMPLES = ''' +- name: CHANGE HOSTNAME + community.fortios.fmgr_device_config: + device_hostname: "ChangedbyAnsible" + device_unique_name: "FGT1" + +- name: EDIT INTERFACE INFORMATION + community.fortios.fmgr_device_config: + adom: "root" + device_unique_name: "FGT2" + interface: "port3" + interface_ip: "10.1.1.1/24" + interface_allow_access: "ping, telnet, https" + +- name: INSTALL CONFIG + community.fortios.fmgr_device_config: + adom: "root" + device_unique_name: "FGT1" + install_config: "enable" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods + + +def update_device_hostname(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + datagram = { + "hostname": paramgram["device_hostname"] + } + + url = "pm/config/device/{device_name}/global/system/global".format(device_name=paramgram["device_unique_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE) + return response + + +def update_device_interface(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + access_list = list() + allow_access_list = paramgram["interface_allow_access"].replace(' ', '') + access_list = allow_access_list.split(',') + + datagram = { + "allowaccess": access_list, + "ip": paramgram["interface_ip"] + } + + url = "/pm/config/device/{device_name}/global/system/interface" \ + "/{interface}".format(device_name=paramgram["device_unique_name"], interface=paramgram["interface"]) + response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE) + return response + + +def exec_config(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + datagram = { + "scope": { + "name": paramgram["device_unique_name"] + }, + "adom": paramgram["adom"], + "flags": "none" + } + + url = "/securityconsole/install/device" + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + device_unique_name=dict(required=True, type="str"), + device_hostname=dict(required=False, type="str"), + interface=dict(required=False, type="str"), + interface_ip=dict(required=False, type="str"), + interface_allow_access=dict(required=False, type="str"), + install_config=dict(required=False, type="str", default="disable"), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + paramgram = { + "device_unique_name": module.params["device_unique_name"], + "device_hostname": module.params["device_hostname"], + "interface": module.params["interface"], + "interface_ip": module.params["interface_ip"], + "interface_allow_access": module.params["interface_allow_access"], + "install_config": module.params["install_config"], + "adom": module.params["adom"] + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + try: + if paramgram["device_hostname"] is not None: + results = update_device_hostname(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + if paramgram["interface_ip"] is not None or paramgram["interface_allow_access"] is not None: + results = update_device_interface(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + if paramgram["install_config"] == "enable": + results = exec_config(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py new file mode 100644 index 000000000..9c8c0ad60 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py @@ -0,0 +1,323 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_device_group +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Alter FortiManager device groups. +description: + - Add or edit device groups and assign devices to device groups FortiManager Device Manager using JSON RPC API. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + vdom: + description: + - The VDOM of the Fortigate you want to add, must match the device in FMGR. Usually root. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + grp_name: + description: + - The name of the device group. + required: false + + grp_desc: + description: + - The description of the device group. + required: false + + grp_members: + description: + - A comma separated list of device names or device groups to be added as members to the device group. + - If Group Members are defined, and mode="delete", only group members will be removed. + - If you want to delete a group itself, you must omit this parameter from the task in playbook. + required: false + +''' + + +EXAMPLES = ''' +- name: CREATE DEVICE GROUP + community.fortios.fmgr_device_group: + grp_name: "TestGroup" + grp_desc: "CreatedbyAnsible" + adom: "ansible" + mode: "add" + +- name: CREATE DEVICE GROUP 2 + community.fortios.fmgr_device_group: + grp_name: "AnsibleGroup" + grp_desc: "CreatedbyAnsible" + adom: "ansible" + mode: "add" + +- name: ADD DEVICES TO DEVICE GROUP + community.fortios.fmgr_device_group: + mode: "add" + grp_name: "TestGroup" + grp_members: "FGT1,FGT2" + adom: "ansible" + vdom: "root" + +- name: REMOVE DEVICES TO DEVICE GROUP + community.fortios.fmgr_device_group: + mode: "delete" + grp_name: "TestGroup" + grp_members: "FGT1,FGT2" + adom: "ansible" + +- name: DELETE DEVICE GROUP + community.fortios.fmgr_device_group: + grp_name: "AnsibleGroup" + grp_desc: "CreatedbyAnsible" + mode: "delete" + adom: "ansible" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def get_groups(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + "method": "get" + } + + url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"]) + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + return response + + +def add_device_group(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + mode = paramgram["mode"] + + datagram = { + "name": paramgram["grp_name"], + "desc": paramgram["grp_desc"], + "os_type": "fos" + } + + url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"]) + + # IF MODE = SET -- USE THE 'SET' API CALL MODE + if mode == "set": + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE + elif mode == "update": + response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE) + # IF MODE = ADD -- USE THE 'ADD' API CALL MODE + elif mode == "add": + response = fmgr.process_request(url, datagram, FMGRMethods.ADD) + + return response + + +def delete_device_group(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + + datagram = { + "adom": paramgram["adom"], + "name": paramgram["grp_name"] + } + + url = '/dvmdb/adom/{adom}/group/{grp_name}'.format(adom=paramgram["adom"], grp_name=paramgram["grp_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.DELETE) + return response + + +def add_group_member(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + device_member_list = paramgram["grp_members"].replace(' ', '') + device_member_list = device_member_list.split(',') + + for dev_name in device_member_list: + datagram = {'name': dev_name, 'vdom': paramgram["vdom"]} + + url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"], + grp_name=paramgram["grp_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.ADD) + + return response + + +def delete_group_member(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + device_member_list = paramgram["grp_members"].replace(' ', '') + device_member_list = device_member_list.split(',') + + for dev_name in device_member_list: + datagram = {'name': dev_name, 'vdom': paramgram["vdom"]} + + url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"], + grp_name=paramgram["grp_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.DELETE) + + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + vdom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + grp_desc=dict(required=False, type="str"), + grp_name=dict(required=True, type="str"), + grp_members=dict(required=False, type="str"), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + paramgram = { + "mode": module.params["mode"], + "grp_name": module.params["grp_name"], + "grp_desc": module.params["grp_desc"], + "grp_members": module.params["grp_members"], + "adom": module.params["adom"], + "vdom": module.params["vdom"] + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + try: + # PROCESS THE GROUP ADDS FIRST + if paramgram["grp_name"] is not None and paramgram["mode"] in ["add", "set", "update"]: + # add device group + results = add_device_group(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + # PROCESS THE GROUP MEMBER ADDS + if paramgram["grp_members"] is not None and paramgram["mode"] in ["add", "set", "update"]: + # assign devices to device group + results = add_group_member(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + # PROCESS THE GROUP MEMBER DELETES + if paramgram["grp_members"] is not None and paramgram["mode"] == "delete": + # remove devices grom a group + results = delete_group_member(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + # PROCESS THE GROUP DELETES, ONLY IF GRP_MEMBERS IS NOT NULL TOO + if paramgram["grp_name"] is not None and paramgram["mode"] == "delete" and paramgram["grp_members"] is None: + # delete device group + results = delete_device_group(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py new file mode 100644 index 000000000..c71886943 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py @@ -0,0 +1,1546 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_device_provision_template +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manages Device Provisioning Templates in FortiManager. +description: + - Allows the editing and assignment of device provisioning templates in FortiManager. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: true + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values. + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + device_unique_name: + description: + - The unique device's name that you are editing. + required: True + + provisioning_template: + description: + - The provisioning template you want to apply (default = default). + required: True + + provision_targets: + description: + - The friendly names of devices in FortiManager to assign the provisioning template to. CSV separated list. + required: True + + snmp_status: + description: + - Enables or disables SNMP globally. + required: False + choices: ["enable", "disable"] + + snmp_v2c_query_port: + description: + - Sets the snmp v2c community query port. + required: False + + snmp_v2c_trap_port: + description: + - Sets the snmp v2c community trap port. + required: False + + snmp_v2c_status: + description: + - Enables or disables the v2c community specified. + required: False + choices: ["enable", "disable"] + + snmp_v2c_trap_status: + description: + - Enables or disables the v2c community specified for traps. + required: False + choices: ["enable", "disable"] + + snmp_v2c_query_status: + description: + - Enables or disables the v2c community specified for queries. + required: False + choices: ["enable", "disable"] + + snmp_v2c_name: + description: + - Specifies the v2c community name. + required: False + + snmp_v2c_id: + description: + - Primary key for the snmp community. this must be unique! + required: False + + snmp_v2c_trap_src_ipv4: + description: + - Source ip the traps should come from IPv4. + required: False + + snmp_v2c_trap_hosts_ipv4: + description: > + - IPv4 addresses of the hosts that should get SNMP v2c traps, comma separated, must include mask + ("10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"). + required: False + + snmp_v2c_query_hosts_ipv4: + description: > + - IPv4 addresses or subnets that are allowed to query SNMP v2c, comma separated + ("10.7.220.59 255.255.255.0, 10.7.220.0 255.255.255.0"). + required: False + + snmpv3_auth_proto: + description: + - SNMPv3 auth protocol. + required: False + choices: ["md5", "sha"] + + snmpv3_auth_pwd: + description: + - SNMPv3 auth pwd __ currently not encrypted! ensure this file is locked down permissions wise! + required: False + + snmpv3_name: + description: + - SNMPv3 user name. + required: False + + snmpv3_notify_hosts: + description: + - List of ipv4 hosts to send snmpv3 traps to. Comma separated IPv4 list. + required: False + + snmpv3_priv_proto: + description: + - SNMPv3 priv protocol. + required: False + choices: ["aes", "des", "aes256", "aes256cisco"] + + snmpv3_priv_pwd: + description: + - SNMPv3 priv pwd currently not encrypted! ensure this file is locked down permissions wise! + required: False + + snmpv3_queries: + description: + - Allow snmpv3_queries. + required: False + choices: ["enable", "disable"] + + snmpv3_query_port: + description: + - SNMPv3 query port. + required: False + + snmpv3_security_level: + description: + - SNMPv3 security level. + required: False + choices: ["no-auth-no-priv", "auth-no-priv", "auth-priv"] + + snmpv3_source_ip: + description: + - SNMPv3 source ipv4 address for traps. + required: False + + snmpv3_status: + description: + - SNMPv3 user is enabled or disabled. + required: False + choices: ["enable", "disable"] + + snmpv3_trap_rport: + description: + - SNMPv3 trap remote port. + required: False + + snmpv3_trap_status: + description: + - SNMPv3 traps is enabled or disabled. + required: False + choices: ["enable", "disable"] + + syslog_port: + description: + - Syslog port that will be set. + required: False + + syslog_server: + description: + - Server the syslogs will be sent to. + required: False + + syslog_status: + description: + - Enables or disables syslogs. + required: False + choices: ["enable", "disable"] + + syslog_mode: + description: + - Remote syslog logging over UDP/Reliable TCP. + - choice | udp | Enable syslogging over UDP. + - choice | legacy-reliable | Enable legacy reliable syslogging by RFC3195 (Reliable Delivery for Syslog). + - choice | reliable | Enable reliable syslogging by RFC6587 (Transmission of Syslog Messages over TCP). + required: false + choices: ["udp", "legacy-reliable", "reliable"] + default: "udp" + + syslog_filter: + description: + - Sets the logging level for syslog. + required: False + choices: ["emergency", "alert", "critical", "error", "warning", "notification", "information", "debug"] + + syslog_facility: + description: + - Remote syslog facility. + - choice | kernel | Kernel messages. + - choice | user | Random user-level messages. + - choice | mail | Mail system. + - choice | daemon | System daemons. + - choice | auth | Security/authorization messages. + - choice | syslog | Messages generated internally by syslog. + - choice | lpr | Line printer subsystem. + - choice | news | Network news subsystem. + - choice | uucp | Network news subsystem. + - choice | cron | Clock daemon. + - choice | authpriv | Security/authorization messages (private). + - choice | ftp | FTP daemon. + - choice | ntp | NTP daemon. + - choice | audit | Log audit. + - choice | alert | Log alert. + - choice | clock | Clock daemon. + - choice | local0 | Reserved for local use. + - choice | local1 | Reserved for local use. + - choice | local2 | Reserved for local use. + - choice | local3 | Reserved for local use. + - choice | local4 | Reserved for local use. + - choice | local5 | Reserved for local use. + - choice | local6 | Reserved for local use. + - choice | local7 | Reserved for local use. + required: false + choices: ["kernel", "user", "mail", "daemon", "auth", "syslog", + "lpr", "news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit", + "alert", "clock", "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"] + default: "syslog" + + syslog_enc_algorithm: + description: + - Enable/disable reliable syslogging with TLS encryption. + - choice | high | SSL communication with high encryption algorithms. + - choice | low | SSL communication with low encryption algorithms. + - choice | disable | Disable SSL communication. + - choice | high-medium | SSL communication with high and medium encryption algorithms. + required: false + choices: ["high", "low", "disable", "high-medium"] + default: "disable" + + syslog_certificate: + description: + - Certificate used to communicate with Syslog server if encryption on. + required: false + + ntp_status: + description: + - Enables or disables ntp. + required: False + choices: ["enable", "disable"] + + ntp_sync_interval: + description: + - Sets the interval in minutes for ntp sync. + required: False + + ntp_type: + description: + - Enables fortiguard servers or custom servers are the ntp source. + required: False + choices: ["fortiguard", "custom"] + + ntp_server: + description: + - Only used with custom ntp_type -- specifies IP of server to sync to -- comma separated ip addresses for multiples. + required: False + + ntp_auth: + description: + - Enables or disables ntp authentication. + required: False + choices: ["enable", "disable"] + + ntp_auth_pwd: + description: + - Sets the ntp auth password. + required: False + + ntp_v3: + description: + - Enables or disables ntpv3 (default is ntpv4). + required: False + choices: ["enable", "disable"] + + admin_https_redirect: + description: + - Enables or disables https redirect from http. + required: False + choices: ["enable", "disable"] + + admin_https_port: + description: + - SSL admin gui port number. + required: False + + admin_http_port: + description: + - Non-SSL admin gui port number. + required: False + + admin_timeout: + description: + - Admin timeout in minutes. + required: False + + admin_language: + description: + - Sets the admin gui language. + required: False + choices: ["english", "simch", "japanese", "korean", "spanish", "trach", "french", "portuguese"] + + admin_switch_controller: + description: + - Enables or disables the switch controller. + required: False + choices: ["enable", "disable"] + + admin_gui_theme: + description: + - Changes the admin gui theme. + required: False + choices: ["green", "red", "blue", "melongene", "mariner"] + + admin_enable_fortiguard: + description: + - Enables FortiGuard security updates to their default settings. + required: False + choices: ["none", "direct", "this-fmg"] + + admin_fortianalyzer_target: + description: + - Configures faz target. + required: False + + admin_fortiguard_target: + description: + - Configures fortiguard target. + - admin_enable_fortiguard must be set to "direct". + required: False + + smtp_username: + description: + - SMTP auth username. + required: False + + smtp_password: + description: + - SMTP password. + required: False + + smtp_port: + description: + - SMTP port number. + required: False + + smtp_replyto: + description: + - SMTP reply to address. + required: False + + smtp_conn_sec: + description: + - defines the ssl level for smtp. + required: False + choices: ["none", "starttls", "smtps"] + + smtp_server: + description: + - SMTP server ipv4 address. + required: False + + smtp_source_ipv4: + description: + - SMTP source ip address. + required: False + + smtp_validate_cert: + description: + - Enables or disables valid certificate checking for smtp. + required: False + choices: ["enable", "disable"] + + dns_suffix: + description: + - Sets the local dns domain suffix. + required: False + + dns_primary_ipv4: + description: + - primary ipv4 dns forwarder. + required: False + + dns_secondary_ipv4: + description: + - secondary ipv4 dns forwarder. + required: False + + delete_provisioning_template: + description: + - If specified, all other options are ignored. The specified provisioning template will be deleted. + required: False + +''' + + +EXAMPLES = ''' +- name: SET SNMP SYSTEM INFO + community.fortios.fmgr_device_provision_template: + provisioning_template: "default" + snmp_status: "enable" + mode: "set" + +- name: SET SNMP SYSTEM INFO ANSIBLE ADOM + community.fortios.fmgr_device_provision_template: + provisioning_template: "default" + snmp_status: "enable" + mode: "set" + adom: "ansible" + +- name: SET SNMP SYSTEM INFO different template (SNMPv2) + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + snmp_status: "enable" + mode: "set" + adom: "ansible" + snmp_v2c_query_port: "162" + snmp_v2c_trap_port: "161" + snmp_v2c_status: "enable" + snmp_v2c_trap_status: "enable" + snmp_v2c_query_status: "enable" + snmp_v2c_name: "ansibleV2c" + snmp_v2c_id: "1" + snmp_v2c_trap_src_ipv4: "10.7.220.41" + snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255" + snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0" + +- name: SET SNMP SYSTEM INFO different template (SNMPv3) + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + snmp_status: "enable" + mode: "set" + adom: "ansible" + snmpv3_auth_proto: "sha" + snmpv3_auth_pwd: "fortinet" + snmpv3_name: "ansibleSNMPv3" + snmpv3_notify_hosts: "10.7.220.59,10.7.220.60" + snmpv3_priv_proto: "aes256" + snmpv3_priv_pwd: "fortinet" + snmpv3_queries: "enable" + snmpv3_query_port: "161" + snmpv3_security_level: "auth_priv" + snmpv3_source_ip: "0.0.0.0" + snmpv3_status: "enable" + snmpv3_trap_rport: "162" + snmpv3_trap_status: "enable" + +- name: SET SYSLOG INFO + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + syslog_server: "10.7.220.59" + syslog_port: "514" + syslog_mode: "disable" + syslog_status: "enable" + syslog_filter: "information" + +- name: SET NTP TO FORTIGUARD + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + ntp_status: "enable" + ntp_sync_interval: "60" + type: "fortiguard" + +- name: SET NTP TO CUSTOM SERVER + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + ntp_status: "enable" + ntp_sync_interval: "60" + ntp_type: "custom" + ntp_server: "10.7.220.32,10.7.220.1" + ntp_auth: "enable" + ntp_auth_pwd: "fortinet" + ntp_v3: "disable" + +- name: SET ADMIN GLOBAL SETTINGS + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + admin_https_redirect: "enable" + admin_https_port: "4433" + admin_http_port: "8080" + admin_timeout: "30" + admin_language: "english" + admin_switch_controller: "enable" + admin_gui_theme: "blue" + admin_enable_fortiguard: "direct" + admin_fortiguard_target: "10.7.220.128" + admin_fortianalyzer_target: "10.7.220.61" + +- name: SET CUSTOM SMTP SERVER + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + smtp_username: "ansible" + smtp_password: "fortinet" + smtp_port: "25" + smtp_replyto: "ansible@do-not-reply.com" + smtp_conn_sec: "starttls" + smtp_server: "10.7.220.32" + smtp_source_ipv4: "0.0.0.0" + smtp_validate_cert: "disable" + +- name: SET DNS SERVERS + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + dns_suffix: "ansible.local" + dns_primary_ipv4: "8.8.8.8" + dns_secondary_ipv4: "4.4.4.4" + +- name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER + community.fortios.fmgr_device_provision_template: + provisioning_template: "ansibleTest" + mode: "set" + adom: "ansible" + provision_targets: "FGT1, FGT2" + +- name: DELETE ENTIRE PROVISIONING TEMPLATE + community.fortios.fmgr_device_provision_template: + delete_provisioning_template: "ansibleTest" + mode: "delete" + adom: "ansible" + +''' +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def get_devprof(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + response = DEFAULT_RESULT_OBJ + datagram = {} + + url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"], name=paramgram["provisioning_template"]) + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + + return response + + +def set_devprof(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add', 'update']: + datagram = { + "name": paramgram["provisioning_template"], + "type": "devprof", + "description": "CreatedByAnsible", + } + url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]) + + elif paramgram["mode"] == "delete": + datagram = {} + + url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"], + name=paramgram["delete_provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def get_devprof_scope(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + response = DEFAULT_RESULT_OBJ + datagram = { + "name": paramgram["provisioning_template"], + "type": "devprof", + "description": "CreatedByAnsible", + } + + url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]) + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + + return response + + +def set_devprof_scope(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add', 'update']: + datagram = { + "name": paramgram["provisioning_template"], + "type": "devprof", + "description": "CreatedByAnsible", + } + + targets = [] + for target in paramgram["provision_targets"].split(","): + # split the host on the space to get the mask out + new_target = {"name": target.strip()} + targets.append(new_target) + + datagram["scope member"] = targets + + url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]) + + elif paramgram["mode"] == "delete": + datagram = { + "name": paramgram["provisioning_template"], + "type": "devprof", + "description": "CreatedByAnsible", + "scope member": paramgram["targets_to_add"] + } + + url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]) + + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + return response + + +def set_devprof_snmp(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + datagram = { + "status": paramgram["snmp_status"] + } + url = "/pm/config/adom/{adom}/devprof/" \ + "{provisioning_template}/system/snmp/sysinfo".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + return response + + +def set_devprof_snmp_v2c(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add', 'update']: + datagram = { + "query-v2c-port": paramgram["snmp_v2c_query_port"], + "trap-v2c-rport": paramgram["snmp_v2c_trap_port"], + "status": paramgram["snmp_v2c_status"], + "trap-v2c-status": paramgram["snmp_v2c_trap_status"], + "query-v2c-status": paramgram["snmp_v2c_query_status"], + "name": paramgram["snmp_v2c_name"], + "id": paramgram["snmp_v2c_id"], + "meta fields": dict(), + "hosts": list(), + "events": 411578417151, + "query-v1-status": 0, + "query-v1-port": 161, + "trap-v1-status": 0, + "trap-v1-lport": 162, + "trap-v1-rport": 162, + "trap-v2c-lport": 162, + } + + # BUILD THE HOST STRINGS + id_counter = 1 + if paramgram["snmp_v2c_trap_hosts_ipv4"] or paramgram["snmp_v2c_query_hosts_ipv4"]: + hosts = [] + if paramgram["snmp_v2c_query_hosts_ipv4"]: + for ipv4_host in paramgram["snmp_v2c_query_hosts_ipv4"].strip().split(","): + # split the host on the space to get the mask out + new_ipv4_host = {"ha-direct": "enable", + "host-type": "query", + "id": id_counter, + "ip": ipv4_host.strip().split(), + "meta fields": {}, + "source-ip": "0.0.0.0"} + hosts.append(new_ipv4_host) + id_counter += 1 + + if paramgram["snmp_v2c_trap_hosts_ipv4"]: + for ipv4_host in paramgram["snmp_v2c_trap_hosts_ipv4"].strip().split(","): + # split the host on the space to get the mask out + new_ipv4_host = {"ha-direct": "enable", + "host-type": "trap", + "id": id_counter, + "ip": ipv4_host.strip().split(), + "meta fields": {}, + "source-ip": paramgram["snmp_v2c_trap_src_ipv4"]} + hosts.append(new_ipv4_host) + id_counter += 1 + datagram["hosts"] = hosts + + url = "/pm/config/adom/{adom}/devprof/" \ + "{provisioning_template}/system/snmp/community".format(adom=adom, + provisioning_template=paramgram[ + "provisioning_template"]) + elif paramgram["mode"] == "delete": + datagram = { + "confirm": 1 + } + + url = "/pm/config/adom/{adom}/" \ + "devprof/{provisioning_template}/" \ + "system/snmp/community/{snmp_v2c_id}".format(adom=adom, + provisioning_template=paramgram["provisioning_template"], + snmp_v2c_id=paramgram["snmp_v2c_id"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_snmp_v3(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add', 'update']: + datagram = {} + datagram["auth-pwd"] = paramgram["snmpv3_auth_pwd"] + datagram["priv-pwd"] = paramgram["snmpv3_priv_pwd"] + datagram["trap-rport"] = paramgram["snmpv3_trap_rport"] + datagram["query-port"] = paramgram["snmpv3_query_port"] + datagram["name"] = paramgram["snmpv3_name"] + datagram["notify-hosts"] = paramgram["snmpv3_notify_hosts"].strip().split(",") + datagram["events"] = 1647387997183 + datagram["trap-lport"] = 162 + + datagram["source-ip"] = paramgram["snmpv3_source_ip"] + datagram["ha-direct"] = 0 + + url = "/pm/config/adom/{adom}/" \ + "devprof/{provisioning_template}/" \ + "system/snmp/user".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + elif paramgram["mode"] == "delete": + datagram = { + "confirm": 1 + } + + url = "/pm/config/adom/{adom}/devprof/" \ + "{provisioning_template}/system/snmp" \ + "/user/{snmpv3_name}".format(adom=adom, + provisioning_template=paramgram["provisioning_template"], + snmpv3_name=paramgram["snmpv3_name"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_syslog(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + + datagram = { + "status": paramgram["syslog_status"], + "port": paramgram["syslog_port"], + "server": paramgram["syslog_server"], + "mode": paramgram["syslog_mode"], + "facility": paramgram["syslog_facility"] + } + + if paramgram["mode"] in ['set', 'add', 'update']: + if paramgram["syslog_enc_algorithm"] in ["high", "low", "high-medium"] \ + and paramgram["syslog_certificate"] is not None: + datagram["certificate"] = paramgram["certificate"] + datagram["enc-algorithm"] = paramgram["syslog_enc_algorithm"] + + url = "/pm/config/adom/{adom}/" \ + "devprof/{provisioning_template}/" \ + "log/syslogd/setting".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + elif paramgram["mode"] == "delete": + url = "/pm/config/adom/{adom}/" \ + "devprof/{provisioning_template}/" \ + "log/syslogd/setting".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_syslog_filter(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + datagram = { + "severity": paramgram["syslog_filter"] + } + response = DEFAULT_RESULT_OBJ + + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/log/syslogd/filter".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_ntp(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + + # IF SET TO FORTIGUARD, BUILD A STRING SPECIFIC TO THAT + if paramgram["ntp_type"] == "fortiguard": + datagram = {} + if paramgram["ntp_status"] == "enable": + datagram["ntpsync"] = 1 + if paramgram["ntp_status"] == "disable": + datagram["ntpsync"] = 0 + if paramgram["ntp_sync_interval"] is None: + datagram["syncinterval"] = 1 + else: + datagram["syncinterval"] = paramgram["ntp_sync_interval"] + + datagram["type"] = 0 + + # IF THE NTP TYPE IS CUSTOM BUILD THE SERVER LIST + if paramgram["ntp_type"] == "custom": + id_counter = 0 + key_counter = 0 + ntpservers = [] + datagram = {} + if paramgram["ntp_status"] == "enable": + datagram["ntpsync"] = 1 + if paramgram["ntp_status"] == "disable": + datagram["ntpsync"] = 0 + try: + datagram["syncinterval"] = paramgram["ntp_sync_interval"] + except BaseException: + datagram["syncinterval"] = 1 + datagram["type"] = 1 + + for server in paramgram["ntp_server"].strip().split(","): + id_counter += 1 + server_fields = dict() + + key_counter += 1 + if paramgram["ntp_auth"] == "enable": + server_fields["authentication"] = 1 + server_fields["key"] = paramgram["ntp_auth_pwd"] + server_fields["key-id"] = key_counter + else: + server_fields["authentication"] = 0 + server_fields["key"] = "" + server_fields["key-id"] = key_counter + + if paramgram["ntp_v3"] == "enable": + server_fields["ntp_v3"] = 1 + else: + server_fields["ntp_v3"] = 0 + + # split the host on the space to get the mask out + new_ntp_server = {"authentication": server_fields["authentication"], + "id": id_counter, "key": server_fields["key"], + "key-id": id_counter, "ntpv3": server_fields["ntp_v3"], + "server": server} + ntpservers.append(new_ntp_server) + datagram["ntpserver"] = ntpservers + + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/system/ntp".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_admin(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + datagram = { + "admin-https-redirect": paramgram["admin_https_redirect"], + "admin-port": paramgram["admin_http_port"], + "admin-sport": paramgram["admin_https_port"], + "admintimeout": paramgram["admin_timeout"], + "language": paramgram["admin_language"], + "gui-theme": paramgram["admin_gui_theme"], + "switch-controller": paramgram["admin_switch_controller"], + } + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/system/global".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_smtp(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + datagram = { + "port": paramgram["smtp_port"], + "reply-to": paramgram["smtp_replyto"], + "server": paramgram["smtp_server"], + "source-ip": paramgram["smtp_source_ipv4"] + } + + if paramgram["smtp_username"]: + datagram["authenticate"] = 1 + datagram["username"] = paramgram["smtp_username"] + datagram["password"] = paramgram["smtp_password"] + + if paramgram["smtp_conn_sec"] == "none": + datagram["security"] = 0 + if paramgram["smtp_conn_sec"] == "starttls": + datagram["security"] = 1 + if paramgram["smtp_conn_sec"] == "smtps": + datagram["security"] = 2 + + if paramgram["smtp_validate_cert"] == "enable": + datagram["validate-server"] = 1 + else: + datagram["validate-server"] = 0 + + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/system/email-server".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_dns(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + datagram = { + "domain": paramgram["dns_suffix"], + "primary": paramgram["dns_primary_ipv4"], + "secondary": paramgram["dns_secondary_ipv4"], + } + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/system/dns".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_toggle_fg(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + response = DEFAULT_RESULT_OBJ + datagram = {} + if paramgram["admin_enable_fortiguard"] in ["direct", "this-fmg"]: + datagram["include-default-servers"] = "enable" + elif paramgram["admin_enable_fortiguard"] == "none": + datagram["include-default-servers"] = "disable" + + datagram["server-list"] = list() + + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/system/central-management".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + + return response + + +def set_devprof_fg(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + datagram = { + "target": paramgram["admin_enable_fortiguard"], + "target-ip": None + } + + if paramgram["mode"] in ['set', 'add', 'update']: + if paramgram["admin_fortiguard_target"] is not None and datagram["target"] == "direct": + datagram["target-ip"] = paramgram["admin_fortiguard_target"] + + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/device/profile/fortiguard".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def set_devprof_faz(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + paramgram["mode"] = paramgram["mode"] + adom = paramgram["adom"] + response = DEFAULT_RESULT_OBJ + datagram = { + "target-ip": paramgram["admin_fortianalyzer_target"], + "target": "others", + } + url = "/pm/config/adom/{adom}" \ + "/devprof/{provisioning_template}" \ + "/device/profile/fortianalyzer".format(adom=adom, + provisioning_template=paramgram["provisioning_template"]) + if paramgram["mode"] == "delete": + datagram["hastarget"] = "False" + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + provisioning_template=dict(required=False, type="str"), + provision_targets=dict(required=False, type="str"), + + device_unique_name=dict(required=False, type="str"), + snmp_status=dict(required=False, type="str", choices=["enable", "disable"]), + snmp_v2c_query_port=dict(required=False, type="int"), + snmp_v2c_trap_port=dict(required=False, type="int"), + snmp_v2c_status=dict(required=False, type="str", choices=["enable", "disable"]), + snmp_v2c_trap_status=dict(required=False, type="str", choices=["enable", "disable"]), + snmp_v2c_query_status=dict(required=False, type="str", choices=["enable", "disable"]), + snmp_v2c_name=dict(required=False, type="str", no_log=True), + snmp_v2c_id=dict(required=False, type="int"), + snmp_v2c_trap_src_ipv4=dict(required=False, type="str"), + snmp_v2c_trap_hosts_ipv4=dict(required=False, type="str"), + snmp_v2c_query_hosts_ipv4=dict(required=False, type="str"), + + snmpv3_auth_proto=dict(required=False, type="str", choices=["md5", "sha"]), + snmpv3_auth_pwd=dict(required=False, type="str", no_log=True), + snmpv3_name=dict(required=False, type="str"), + snmpv3_notify_hosts=dict(required=False, type="str"), + snmpv3_priv_proto=dict(required=False, type="str", choices=["aes", "des", "aes256", "aes256cisco"]), + snmpv3_priv_pwd=dict(required=False, type="str", no_log=True), + snmpv3_queries=dict(required=False, type="str", choices=["enable", "disable"]), + snmpv3_query_port=dict(required=False, type="int"), + snmpv3_security_level=dict(required=False, type="str", + choices=["no-auth-no-priv", "auth-no-priv", "auth-priv"]), + snmpv3_source_ip=dict(required=False, type="str"), + snmpv3_status=dict(required=False, type="str", choices=["enable", "disable"]), + snmpv3_trap_rport=dict(required=False, type="int"), + snmpv3_trap_status=dict(required=False, type="str", choices=["enable", "disable"]), + + syslog_port=dict(required=False, type="int"), + syslog_server=dict(required=False, type="str"), + syslog_mode=dict(required=False, type="str", choices=["udp", "legacy-reliable", "reliable"], default="udp"), + syslog_status=dict(required=False, type="str", choices=["enable", "disable"]), + syslog_filter=dict(required=False, type="str", choices=["emergency", "alert", "critical", "error", + "warning", "notification", "information", "debug"]), + syslog_enc_algorithm=dict(required=False, type="str", choices=["high", "low", "disable", "high-medium"], + default="disable"), + syslog_facility=dict(required=False, type="str", choices=["kernel", "user", "mail", "daemon", "auth", + "syslog", "lpr", "news", "uucp", "cron", "authpriv", + "ftp", "ntp", "audit", "alert", "clock", "local0", + "local1", "local2", "local3", "local4", "local5", + "local6", "local7"], default="syslog"), + syslog_certificate=dict(required=False, type="str"), + + ntp_status=dict(required=False, type="str", choices=["enable", "disable"]), + ntp_sync_interval=dict(required=False, type="int"), + ntp_type=dict(required=False, type="str", choices=["fortiguard", "custom"]), + ntp_server=dict(required=False, type="str"), + ntp_auth=dict(required=False, type="str", choices=["enable", "disable"]), + ntp_auth_pwd=dict(required=False, type="str", no_log=True), + ntp_v3=dict(required=False, type="str", choices=["enable", "disable"]), + + admin_https_redirect=dict(required=False, type="str", choices=["enable", "disable"]), + admin_https_port=dict(required=False, type="int"), + admin_http_port=dict(required=False, type="int"), + admin_timeout=dict(required=False, type="int"), + admin_language=dict(required=False, type="str", + choices=["english", "simch", "japanese", "korean", + "spanish", "trach", "french", "portuguese"]), + admin_switch_controller=dict(required=False, type="str", choices=["enable", "disable"]), + admin_gui_theme=dict(required=False, type="str", choices=["green", "red", "blue", "melongene", "mariner"]), + admin_enable_fortiguard=dict(required=False, type="str", choices=["none", "direct", "this-fmg"]), + admin_fortianalyzer_target=dict(required=False, type="str"), + admin_fortiguard_target=dict(required=False, type="str"), + + smtp_username=dict(required=False, type="str"), + smtp_password=dict(required=False, type="str", no_log=True), + smtp_port=dict(required=False, type="int"), + smtp_replyto=dict(required=False, type="str"), + smtp_conn_sec=dict(required=False, type="str", choices=["none", "starttls", "smtps"]), + smtp_server=dict(required=False, type="str"), + smtp_source_ipv4=dict(required=False, type="str"), + smtp_validate_cert=dict(required=False, type="str", choices=["enable", "disable"]), + + dns_suffix=dict(required=False, type="str"), + dns_primary_ipv4=dict(required=False, type="str"), + dns_secondary_ipv4=dict(required=False, type="str"), + delete_provisioning_template=dict(required=False, type="str") + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + paramgram = { + "adom": module.params["adom"], + "mode": module.params["mode"], + "provision_targets": module.params["provision_targets"], + "provisioning_template": module.params["provisioning_template"], + + "snmp_status": module.params["snmp_status"], + "snmp_v2c_query_port": module.params["snmp_v2c_query_port"], + "snmp_v2c_trap_port": module.params["snmp_v2c_trap_port"], + "snmp_v2c_status": module.params["snmp_v2c_status"], + "snmp_v2c_trap_status": module.params["snmp_v2c_trap_status"], + "snmp_v2c_query_status": module.params["snmp_v2c_query_status"], + "snmp_v2c_name": module.params["snmp_v2c_name"], + "snmp_v2c_id": module.params["snmp_v2c_id"], + "snmp_v2c_trap_src_ipv4": module.params["snmp_v2c_trap_src_ipv4"], + "snmp_v2c_trap_hosts_ipv4": module.params["snmp_v2c_trap_hosts_ipv4"], + "snmp_v2c_query_hosts_ipv4": module.params["snmp_v2c_query_hosts_ipv4"], + + "snmpv3_auth_proto": module.params["snmpv3_auth_proto"], + "snmpv3_auth_pwd": module.params["snmpv3_auth_pwd"], + "snmpv3_name": module.params["snmpv3_name"], + "snmpv3_notify_hosts": module.params["snmpv3_notify_hosts"], + "snmpv3_priv_proto": module.params["snmpv3_priv_proto"], + "snmpv3_priv_pwd": module.params["snmpv3_priv_pwd"], + "snmpv3_queries": module.params["snmpv3_queries"], + "snmpv3_query_port": module.params["snmpv3_query_port"], + "snmpv3_security_level": module.params["snmpv3_security_level"], + "snmpv3_source_ip": module.params["snmpv3_source_ip"], + "snmpv3_status": module.params["snmpv3_status"], + "snmpv3_trap_rport": module.params["snmpv3_trap_rport"], + "snmpv3_trap_status": module.params["snmpv3_trap_status"], + + "syslog_port": module.params["syslog_port"], + "syslog_server": module.params["syslog_server"], + "syslog_mode": module.params["syslog_mode"], + "syslog_status": module.params["syslog_status"], + "syslog_filter": module.params["syslog_filter"], + "syslog_facility": module.params["syslog_facility"], + "syslog_enc_algorithm": module.params["syslog_enc_algorithm"], + "syslog_certificate": module.params["syslog_certificate"], + + "ntp_status": module.params["ntp_status"], + "ntp_sync_interval": module.params["ntp_sync_interval"], + "ntp_type": module.params["ntp_type"], + "ntp_server": module.params["ntp_server"], + "ntp_auth": module.params["ntp_auth"], + "ntp_auth_pwd": module.params["ntp_auth_pwd"], + "ntp_v3": module.params["ntp_v3"], + + "admin_https_redirect": module.params["admin_https_redirect"], + "admin_https_port": module.params["admin_https_port"], + "admin_http_port": module.params["admin_http_port"], + "admin_timeout": module.params["admin_timeout"], + "admin_language": module.params["admin_language"], + "admin_switch_controller": module.params["admin_switch_controller"], + "admin_gui_theme": module.params["admin_gui_theme"], + "admin_enable_fortiguard": module.params["admin_enable_fortiguard"], + "admin_fortianalyzer_target": module.params["admin_fortianalyzer_target"], + "admin_fortiguard_target": module.params["admin_fortiguard_target"], + + "smtp_username": module.params["smtp_username"], + "smtp_password": module.params["smtp_password"], + "smtp_port": module.params["smtp_port"], + "smtp_replyto": module.params["smtp_replyto"], + "smtp_conn_sec": module.params["smtp_conn_sec"], + "smtp_server": module.params["smtp_server"], + "smtp_source_ipv4": module.params["smtp_source_ipv4"], + "smtp_validate_cert": module.params["smtp_validate_cert"], + + "dns_suffix": module.params["dns_suffix"], + "dns_primary_ipv4": module.params["dns_primary_ipv4"], + "dns_secondary_ipv4": module.params["dns_secondary_ipv4"], + "delete_provisioning_template": module.params["delete_provisioning_template"] + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + try: + # CHECK IF WE ARE DELETING AN ENTIRE TEMPLATE. IF THAT'S THE CASE DO IT FIRST AND IGNORE THE REST. + if paramgram["delete_provisioning_template"] is not None: + results = set_devprof(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -10, -1], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram), + stop_on_success=True) + except Exception as err: + raise FMGBaseException(err) + + try: + # CHECK TO SEE IF THE DEVPROF TEMPLATE EXISTS + devprof = get_devprof(fmgr, paramgram) + if devprof[0] != 0: + results = set_devprof(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -2], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE SNMP SETTINGS IF THE SNMP_STATUS VARIABLE IS SET + if paramgram["snmp_status"] is not None: + results = set_devprof_snmp(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + # PROCESS THE SNMP V2C COMMUNITY SETTINGS IF THEY ARE ALL HERE + if all(v is not None for v in (paramgram["snmp_v2c_query_port"], paramgram["snmp_v2c_trap_port"], + paramgram["snmp_v2c_status"], paramgram["snmp_v2c_trap_status"], + paramgram["snmp_v2c_query_status"], paramgram["snmp_v2c_name"], + paramgram["snmp_v2c_id"])): + results = set_devprof_snmp_v2c(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -10033], stop_on_success=True, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + # PROCESS THE SNMPV3 USER IF THERE + if all(v is not None for v in ( + [paramgram["snmpv3_auth_proto"], paramgram["snmpv3_auth_pwd"], paramgram["snmpv3_name"], + paramgram["snmpv3_notify_hosts"], paramgram["snmpv3_priv_proto"], + paramgram["snmpv3_priv_pwd"], + paramgram["snmpv3_queries"], + paramgram["snmpv3_query_port"], paramgram["snmpv3_security_level"], + paramgram["snmpv3_source_ip"], + paramgram["snmpv3_status"], paramgram["snmpv3_trap_rport"], paramgram["snmpv3_trap_status"]])): + + results = set_devprof_snmp_v3(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3], + stop_on_success=True, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE SYSLOG SETTINGS IF THE ALL THE NEEDED SYSLOG VARIABLES ARE PRESENT + if all(v is not None for v in [paramgram["syslog_port"], paramgram["syslog_mode"], + paramgram["syslog_server"], paramgram["syslog_status"]]): + # enable syslog in the devprof template + results = set_devprof_syslog(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF THE SYSLOG FILTER IS PRESENT THEN RUN THAT + if paramgram["syslog_filter"] is not None: + results = set_devprof_syslog_filter(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS NTP OPTIONS + if paramgram["ntp_status"]: + # VALIDATE INPUT + if paramgram["ntp_type"] == "custom" and paramgram["ntp_server"] is None: + module.exit_json(msg="You requested custom NTP type but did not provide ntp_server parameter.") + if paramgram["ntp_auth"] == "enable" and paramgram["ntp_auth_pwd"] is None: + module.exit_json( + msg="You requested NTP Authentication but did not provide ntp_auth_pwd parameter.") + + results = set_devprof_ntp(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + try: + # PROCESS THE ADMIN OPTIONS + if any(v is not None for v in ( + paramgram["admin_https_redirect"], paramgram["admin_https_port"], paramgram["admin_http_port"], + paramgram["admin_timeout"], + paramgram["admin_language"], paramgram["admin_switch_controller"], + paramgram["admin_gui_theme"])): + + results = set_devprof_admin(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS FORTIGUARD OPTIONS + if paramgram["admin_enable_fortiguard"] is not None: + + results = set_devprof_toggle_fg(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + results = set_devprof_fg(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE SMTP OPTIONS + if all(v is not None for v in ( + paramgram["smtp_username"], paramgram["smtp_password"], paramgram["smtp_port"], + paramgram["smtp_replyto"], + paramgram["smtp_conn_sec"], paramgram["smtp_server"], + paramgram["smtp_source_ipv4"], paramgram["smtp_validate_cert"])): + + results = set_devprof_smtp(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE DNS OPTIONS + if any(v is not None for v in + (paramgram["dns_suffix"], paramgram["dns_primary_ipv4"], paramgram["dns_secondary_ipv4"])): + results = set_devprof_dns(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE admin_fortianalyzer_target OPTIONS + if paramgram["admin_fortianalyzer_target"] is not None: + + results = set_devprof_faz(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # PROCESS THE PROVISIONING TEMPLATE TARGET PARAMETER + if paramgram["provision_targets"] is not None: + if paramgram["mode"] != "delete": + results = set_devprof_scope(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + if paramgram["mode"] == "delete": + # WE NEED TO FIGURE OUT WHAT'S THERE FIRST, BEFORE WE CAN RUN THIS + targets_to_add = list() + try: + current_scope = get_devprof_scope(fmgr, paramgram) + targets_to_remove = paramgram["provision_targets"].strip().split(",") + targets = current_scope[1][1]["scope member"] + for target in targets: + if target["name"] not in targets_to_remove: + target_append = {"name": target["name"]} + targets_to_add.append(target_append) + except BaseException: + pass + paramgram["targets_to_add"] = targets_to_add + results = set_devprof_scope(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py new file mode 100644 index 000000000..c060c00d2 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py @@ -0,0 +1,661 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwobj_address +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Allows the management of firewall objects in FortiManager +description: + - Allows for the management of IPv4, IPv6, and multicast address objects within FortiManager. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + allow_routing: + description: + - Enable/disable use of this address in the static route configuration. + choices: ['enable', 'disable'] + default: 'disable' + + associated_interface: + description: + - Associated interface name. + + cache_ttl: + description: + - Minimal TTL of individual IP addresses in FQDN cache. Only applies when type = wildcard-fqdn. + + color: + description: + - Color of the object in FortiManager GUI. + - Takes integers 1-32 + default: 22 + + comment: + description: + - Comment for the object in FortiManager. + + country: + description: + - Country name. Required if type = geographic. + + end_ip: + description: + - End IP. Only used when ipv4 = iprange. + + group_members: + description: + - Address group member. If this is defined w/out group_name, the operation will fail. + + group_name: + description: + - Address group name. If this is defined in playbook task, all other options are ignored. + + ipv4: + description: + - Type of IPv4 Object. + - Must not be specified with either multicast or IPv6 parameters. + choices: ['ipmask', 'iprange', 'fqdn', 'wildcard', 'geography', 'wildcard-fqdn', 'group'] + + ipv4addr: + description: + - IP and network mask. If only defining one IP use this parameter. (i.e. 10.7.220.30/255.255.255.255) + - Can also define subnets (i.e. 10.7.220.0/255.255.255.0) + - Also accepts CIDR (i.e. 10.7.220.0/24) + - If Netmask is omitted after IP address, /32 is assumed. + - When multicast is set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet. + + ipv6: + description: + - Puts module into IPv6 mode. + - Must not be specified with either ipv4 or multicast parameters. + choices: ['ip', 'iprange', 'group'] + + ipv6addr: + description: + - IPv6 address in full. (i.e. 2001:0db8:85a3:0000:0000:8a2e:0370:7334) + + fqdn: + description: + - Fully qualified domain name. + + mode: + description: + - Sets one of three modes for managing the object. + choices: ['add', 'set', 'delete'] + default: add + + multicast: + description: + - Manages Multicast Address Objects. + - Sets either a Multicast IP Range or a Broadcast Subnet. + - Must not be specified with either ipv4 or ipv6 parameters. + - When set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet. + - Can create IPv4 Multicast Objects (multicastrange and broadcastmask options -- uses start/end-ip and ipv4addr). + choices: ['multicastrange', 'broadcastmask', 'ip6'] + + name: + description: + - Friendly Name Address object name in FortiManager. + + obj_id: + description: + - Object ID for NSX. + + start_ip: + description: + - Start IP. Only used when ipv4 = iprange. + + visibility: + description: + - Enable/disable address visibility. + choices: ['enable', 'disable'] + default: 'enable' + + wildcard: + description: + - IP address and wildcard netmask. Required if ipv4 = wildcard. + + wildcard_fqdn: + description: + - Wildcard FQDN. Required if ipv4 = wildcard-fqdn. +''' + +EXAMPLES = ''' +- name: ADD IPv4 IP ADDRESS OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "ipmask" + ipv4addr: "10.7.220.30/32" + name: "ansible_v4Obj" + comment: "Created by Ansible" + color: "6" + +- name: ADD IPv4 IP ADDRESS OBJECT MORE OPTIONS + community.fortios.fmgr_fwobj_address: + ipv4: "ipmask" + ipv4addr: "10.7.220.34/32" + name: "ansible_v4Obj_MORE" + comment: "Created by Ansible" + color: "6" + allow_routing: "enable" + cache_ttl: "180" + associated_interface: "port1" + obj_id: "123" + +- name: ADD IPv4 IP ADDRESS SUBNET OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "ipmask" + ipv4addr: "10.7.220.0/255.255.255.128" + name: "ansible_subnet" + comment: "Created by Ansible" + mode: "set" + +- name: ADD IPv4 IP ADDRESS RANGE OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "iprange" + start_ip: "10.7.220.1" + end_ip: "10.7.220.125" + name: "ansible_range" + comment: "Created by Ansible" + +- name: ADD IPv4 IP ADDRESS WILDCARD OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "wildcard" + wildcard: "10.7.220.30/255.255.255.255" + name: "ansible_wildcard" + comment: "Created by Ansible" + +- name: ADD IPv4 IP ADDRESS WILDCARD FQDN OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "wildcard-fqdn" + wildcard_fqdn: "*.myds.com" + name: "Synology myds DDNS service" + comment: "Created by Ansible" + +- name: ADD IPv4 IP ADDRESS FQDN OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "fqdn" + fqdn: "ansible.com" + name: "ansible_fqdn" + comment: "Created by Ansible" + +- name: ADD IPv4 IP ADDRESS GEO OBJECT + community.fortios.fmgr_fwobj_address: + ipv4: "geography" + country: "usa" + name: "ansible_geo" + comment: "Created by Ansible" + +- name: ADD IPv6 ADDRESS + community.fortios.fmgr_fwobj_address: + ipv6: "ip" + ipv6addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + name: "ansible_v6Obj" + comment: "Created by Ansible" + +- name: ADD IPv6 ADDRESS RANGE + community.fortios.fmgr_fwobj_address: + ipv6: "iprange" + start_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + end_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7446" + name: "ansible_v6range" + comment: "Created by Ansible" + +- name: ADD IPv4 IP ADDRESS GROUP + community.fortios.fmgr_fwobj_address: + ipv4: "group" + group_name: "ansibleIPv4Group" + group_members: "ansible_fqdn, ansible_wildcard, ansible_range" + +- name: ADD IPv6 IP ADDRESS GROUP + community.fortios.fmgr_fwobj_address: + ipv6: "group" + group_name: "ansibleIPv6Group" + group_members: "ansible_v6Obj, ansible_v6range" + +- name: ADD MULTICAST RANGE + community.fortios.fmgr_fwobj_address: + multicast: "multicastrange" + start_ip: "224.0.0.251" + end_ip: "224.0.0.251" + name: "ansible_multicastrange" + comment: "Created by Ansible" + +- name: ADD BROADCAST SUBNET + community.fortios.fmgr_fwobj_address: + multicast: "broadcastmask" + ipv4addr: "10.7.220.0/24" + name: "ansible_broadcastSubnet" + comment: "Created by Ansible" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + + +import re +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def fmgr_fwobj_ipv4(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # EVAL THE MODE PARAMETER FOR SET OR ADD + if paramgram["mode"] in ['set', 'add']: + # CREATE THE DATAGRAM DICTIONARY + # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE + # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED + datagram = { + "comment": paramgram["comment"], + "associated-interface": paramgram["associated-interface"], + "cache-ttl": paramgram["cache-ttl"], + "name": paramgram["name"], + "allow-routing": paramgram["allow-routing"], + "color": paramgram["color"], + "meta fields": {}, + "dynamic_mapping": [], + "visibility": paramgram["allow-routing"], + "type": paramgram["ipv4"], + } + + # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO) + if datagram["type"] == "group": + url = '/pm/config/adom/{adom}/obj/firewall/addrgrp'.format(adom=paramgram["adom"]) + else: + url = '/pm/config/adom/{adom}/obj/firewall/address'.format(adom=paramgram["adom"]) + + ######################### + # IF type = 'ipmask' + ######################### + if datagram["type"] == "ipmask": + # CREATE THE SUBNET LIST OBJECT + subnet = [] + # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST + for subnets in paramgram["ipv4addr"].split("/"): + subnet.append(subnets) + + # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER) + # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT. + # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API + if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]): + # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE xxx.xxx.xxx.xxx TO REGEX... + # ... RUN IT THROUGH THE CIDR_TO_NETMASK() FUNCTION + mask = fmgr._tools.cidr_to_netmask(subnet[1]) + # AND THEN UPDATE THE SUBNET LIST OBJECT + subnet[1] = mask + + # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED + datagram["subnet"] = subnet + + ######################### + # IF type = 'iprange' + ######################### + if datagram["type"] == "iprange": + datagram["start-ip"] = paramgram["start-ip"] + datagram["end-ip"] = paramgram["end-ip"] + datagram["subnet"] = ["0.0.0.0", "0.0.0.0"] + + ######################### + # IF type = 'geography' + ######################### + if datagram["type"] == "geography": + datagram["country"] = paramgram["country"] + + ######################### + # IF type = 'wildcard' + ######################### + if datagram["type"] == "wildcard": + + subnet = [] + for subnets in paramgram["wildcard"].split("/"): + subnet.append(subnets) + + if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]): + mask = fmgr._tools.cidr_to_netmask(subnet[1]) + subnet[1] = mask + + datagram["wildcard"] = subnet + + ######################### + # IF type = 'wildcard-fqdn' + ######################### + if datagram["type"] == "wildcard-fqdn": + datagram["wildcard-fqdn"] = paramgram["wildcard-fqdn"] + + ######################### + # IF type = 'fqdn' + ######################### + if datagram["type"] == "fqdn": + datagram["fqdn"] = paramgram["fqdn"] + + ######################### + # IF type = 'group' + ######################### + if datagram["type"] == "group": + datagram = { + "comment": paramgram["comment"], + "name": paramgram["group_name"], + "color": paramgram["color"], + "meta fields": {}, + "dynamic_mapping": [], + "visibility": paramgram["visibility"] + } + + members = [] + group_members = paramgram["group_members"].replace(" ", "") + try: + for member in group_members.split(","): + members.append(member) + except Exception: + pass + + datagram["member"] = members + + # EVAL THE MODE PARAMETER FOR DELETE + if paramgram["mode"] == "delete": + # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT + if paramgram["ipv4"] == "group": + datagram = {} + url = '/pm/config/adom/{adom}/obj/firewall/addrgrp/{name}'.format(adom=paramgram["adom"], + name=paramgram["group_name"]) + # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT + else: + datagram = {} + url = '/pm/config/adom/{adom}/obj/firewall/address/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwobj_ipv6(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # EVAL THE MODE PARAMETER FOR SET OR ADD + if paramgram["mode"] in ['set', 'add']: + # CREATE THE DATAGRAM DICTIONARY + # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE + # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED + datagram = { + "comment": paramgram["comment"], + "name": paramgram["name"], + "color": paramgram["color"], + "dynamic_mapping": [], + "visibility": paramgram["visibility"], + "type": paramgram["ipv6"] + } + + # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO) + if datagram["type"] == "group": + url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6'.format(adom=paramgram["adom"]) + else: + url = '/pm/config/adom/{adom}/obj/firewall/address6'.format(adom=paramgram["adom"]) + + ######################### + # IF type = 'ip' + ######################### + if datagram["type"] == "ip": + datagram["type"] = "ipprefix" + datagram["ip6"] = paramgram["ipv6addr"] + + ######################### + # IF type = 'iprange' + ######################### + if datagram["type"] == "iprange": + datagram["start-ip"] = paramgram["start-ip"] + datagram["end-ip"] = paramgram["end-ip"] + + ######################### + # IF type = 'group' + ######################### + if datagram["type"] == "group": + datagram = None + datagram = { + "comment": paramgram["comment"], + "name": paramgram["group_name"], + "color": paramgram["color"], + "visibility": paramgram["visibility"] + } + + members = [] + group_members = paramgram["group_members"].replace(" ", "") + try: + for member in group_members.split(","): + members.append(member) + except Exception: + pass + + datagram["member"] = members + + # EVAL THE MODE PARAMETER FOR DELETE + if paramgram["mode"] == "delete": + # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT + if paramgram["ipv6"] == "group": + datagram = {} + url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6/{name}'.format(adom=paramgram["adom"], + name=paramgram["group_name"]) + # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT + else: + datagram = {} + url = '/pm/config/adom/{adom}/obj/firewall/address6/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwobj_multicast(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # EVAL THE MODE PARAMETER FOR SET OR ADD + if paramgram["mode"] in ['set', 'add']: + # CREATE THE DATAGRAM DICTIONARY + # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE + # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED + datagram = { + "associated-interface": paramgram["associated-interface"], + "comment": paramgram["comment"], + "name": paramgram["name"], + "color": paramgram["color"], + "type": paramgram["multicast"], + "visibility": paramgram["visibility"], + } + + # SET THE CORRECT URL + url = '/pm/config/adom/{adom}/obj/firewall/multicast-address'.format(adom=paramgram["adom"]) + + ######################### + # IF type = 'multicastrange' + ######################### + if paramgram["multicast"] == "multicastrange": + datagram["start-ip"] = paramgram["start-ip"] + datagram["end-ip"] = paramgram["end-ip"] + datagram["subnet"] = ["0.0.0.0", "0.0.0.0"] + + ######################### + # IF type = 'broadcastmask' + ######################### + if paramgram["multicast"] == "broadcastmask": + # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST + subnet = [] + for subnets in paramgram["ipv4addr"].split("/"): + subnet.append(subnets) + # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER) + # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT. + # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API + if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]): + # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE 255.255.255.255 TO REGEX... + # ... RUN IT THROUGH THE fmgr_cidr_to_netmask() FUNCTION + mask = fmgr._tools.cidr_to_netmask(subnet[1]) + # AND THEN UPDATE THE SUBNET LIST OBJECT + subnet[1] = mask + + # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED + datagram["subnet"] = subnet + + # EVAL THE MODE PARAMETER FOR DELETE + if paramgram["mode"] == "delete": + datagram = { + "name": paramgram["name"] + } + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/multicast-address/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "set", "delete"], type="str", default="add"), + + allow_routing=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"), + associated_interface=dict(required=False, type="str"), + cache_ttl=dict(required=False, type="str"), + color=dict(required=False, type="str", default=22), + comment=dict(required=False, type="str"), + country=dict(required=False, type="str"), + fqdn=dict(required=False, type="str"), + name=dict(required=False, type="str"), + start_ip=dict(required=False, type="str"), + end_ip=dict(required=False, type="str"), + ipv4=dict(required=False, type="str", choices=['ipmask', 'iprange', 'fqdn', 'wildcard', + 'geography', 'wildcard-fqdn', 'group']), + visibility=dict(required=False, type="str", choices=['enable', 'disable'], default="enable"), + wildcard=dict(required=False, type="str"), + wildcard_fqdn=dict(required=False, type="str"), + ipv6=dict(required=False, type="str", choices=['ip', 'iprange', 'group']), + group_members=dict(required=False, type="str"), + group_name=dict(required=False, type="str"), + ipv4addr=dict(required=False, type="str"), + ipv6addr=dict(required=False, type="str"), + multicast=dict(required=False, type="str", choices=['multicastrange', 'broadcastmask', 'ip6']), + obj_id=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, + mutually_exclusive=[ + ['ipv4', 'ipv6'], + ['ipv4', 'multicast'], + ['ipv6', 'multicast'] + ]) + paramgram = { + "adom": module.params["adom"], + "allow-routing": module.params["allow_routing"], + "associated-interface": module.params["associated_interface"], + "cache-ttl": module.params["cache_ttl"], + "color": module.params["color"], + "comment": module.params["comment"], + "country": module.params["country"], + "end-ip": module.params["end_ip"], + "fqdn": module.params["fqdn"], + "name": module.params["name"], + "start-ip": module.params["start_ip"], + "visibility": module.params["visibility"], + "wildcard": module.params["wildcard"], + "wildcard-fqdn": module.params["wildcard_fqdn"], + "ipv6": module.params["ipv6"], + "ipv4": module.params["ipv4"], + "group_members": module.params["group_members"], + "group_name": module.params["group_name"], + "ipv4addr": module.params["ipv4addr"], + "ipv6addr": module.params["ipv6addr"], + "multicast": module.params["multicast"], + "mode": module.params["mode"], + "obj-id": module.params["obj_id"], + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr._tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + try: + if paramgram["ipv4"]: + results = fmgr_fwobj_ipv4(fmgr, paramgram) + + elif paramgram["ipv6"]: + results = fmgr_fwobj_ipv6(fmgr, paramgram) + + elif paramgram["multicast"]: + results = fmgr_fwobj_multicast(fmgr, paramgram) + + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + if results is not None: + return module.exit_json(**results[1]) + else: + return module.exit_json(msg="Couldn't find a proper ipv4 or ipv6 or multicast parameter " + "to run in the logic tree. Exiting...") + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py new file mode 100644 index 000000000..a0b39ab16 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py @@ -0,0 +1,442 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwobj_ippool +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Allows the editing of IP Pool Objects within FortiManager. +description: + - Allows users to add/edit/delete IP Pool Objects. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + type: + description: + - IP pool type (overload, one-to-one, fixed port range, or port block allocation). + - choice | overload | IP addresses in the IP pool can be shared by clients. + - choice | one-to-one | One to one mapping. + - choice | fixed-port-range | Fixed port range. + - choice | port-block-allocation | Port block allocation. + required: false + choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"] + + startip: + description: + - First IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0). + required: false + + source_startip: + description: + - First IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx, + Default| 0.0.0.0). + required: false + + source_endip: + description: + - Final IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx, + Default| 0.0.0.0). + required: false + + permit_any_host: + description: + - Enable/disable full cone NAT. + - choice | disable | Disable full cone NAT. + - choice | enable | Enable full cone NAT. + required: false + choices: ["disable", "enable"] + + pba_timeout: + description: + - Port block allocation timeout (seconds). + required: false + + num_blocks_per_user: + description: + - Number of addresses blocks that can be used by a user (1 to 128, default = 8). + required: false + + name: + description: + - IP pool name. + required: false + + endip: + description: + - Final IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0). + required: false + + comments: + description: + - Comment. + required: false + + block_size: + description: + - Number of addresses in a block (64 to 4096, default = 128). + required: false + + associated_interface: + description: + - Associated interface name. + required: false + + arp_reply: + description: + - Enable/disable replying to ARP requests when an IP Pool is added to a policy (default = enable). + - choice | disable | Disable ARP reply. + - choice | enable | Enable ARP reply. + required: false + choices: ["disable", "enable"] + + arp_intf: + description: + - Select an interface from available options that will reply to ARP requests. (If blank, any is selected). + required: false + + dynamic_mapping: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameter.ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + dynamic_mapping_arp_intf: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_arp_reply: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + choices: ["disable", "enable"] + + dynamic_mapping_associated_interface: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_block_size: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_comments: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_endip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_num_blocks_per_user: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_pba_timeout: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_permit_any_host: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + choices: ["disable", "enable"] + + dynamic_mapping_source_endip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_source_startip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_startip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_type: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"] + + +''' + +EXAMPLES = ''' +- name: ADD FMGR_FIREWALL_IPPOOL Overload + community.fortios.fmgr_fwobj_ippool: + mode: "add" + adom: "ansible" + name: "Ansible_pool4_overload" + comments: "Created by ansible" + type: "overload" + + # OPTIONS FOR ALL MODES + startip: "10.10.10.10" + endip: "10.10.10.100" + arp_reply: "enable" + +- name: ADD FMGR_FIREWALL_IPPOOL one-to-one + community.fortios.fmgr_fwobj_ippool: + mode: "add" + adom: "ansible" + name: "Ansible_pool4_121" + comments: "Created by ansible" + type: "one-to-one" + + # OPTIONS FOR ALL MODES + startip: "10.10.20.10" + endip: "10.10.20.100" + arp_reply: "enable" + +- name: ADD FMGR_FIREWALL_IPPOOL FIXED PORT RANGE + community.fortios.fmgr_fwobj_ippool: + mode: "add" + adom: "ansible" + name: "Ansible_pool4_fixed_port" + comments: "Created by ansible" + type: "fixed-port-range" + + # OPTIONS FOR ALL MODES + startip: "10.10.40.10" + endip: "10.10.40.100" + arp_reply: "enable" + # FIXED PORT RANGE OPTIONS + source_startip: "192.168.20.1" + source_endip: "192.168.20.20" + +- name: ADD FMGR_FIREWALL_IPPOOL PORT BLOCK ALLOCATION + community.fortios.fmgr_fwobj_ippool: + mode: "add" + adom: "ansible" + name: "Ansible_pool4_port_block_allocation" + comments: "Created by ansible" + type: "port-block-allocation" + + # OPTIONS FOR ALL MODES + startip: "10.10.30.10" + endip: "10.10.30.100" + arp_reply: "enable" + # PORT BLOCK ALLOCATION OPTIONS + block_size: "128" + num_blocks_per_user: "1" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_fwobj_ippool_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/firewall/ippool'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/ippool/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + type=dict(required=False, type="str", choices=["overload", + "one-to-one", + "fixed-port-range", + "port-block-allocation"]), + startip=dict(required=False, type="str"), + source_startip=dict(required=False, type="str"), + source_endip=dict(required=False, type="str"), + permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]), + pba_timeout=dict(required=False, type="int"), + num_blocks_per_user=dict(required=False, type="int"), + name=dict(required=False, type="str"), + endip=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + block_size=dict(required=False, type="int"), + associated_interface=dict(required=False, type="str"), + arp_reply=dict(required=False, type="str", choices=["disable", "enable"]), + arp_intf=dict(required=False, type="str"), + dynamic_mapping=dict(required=False, type="list"), + dynamic_mapping_arp_intf=dict(required=False, type="str"), + dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_associated_interface=dict(required=False, type="str"), + dynamic_mapping_block_size=dict(required=False, type="int"), + dynamic_mapping_comments=dict(required=False, type="str"), + dynamic_mapping_endip=dict(required=False, type="str"), + dynamic_mapping_num_blocks_per_user=dict(required=False, type="int"), + dynamic_mapping_pba_timeout=dict(required=False, type="int"), + dynamic_mapping_permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_source_endip=dict(required=False, type="str"), + dynamic_mapping_source_startip=dict(required=False, type="str"), + dynamic_mapping_startip=dict(required=False, type="str"), + dynamic_mapping_type=dict(required=False, type="str", choices=["overload", + "one-to-one", + "fixed-port-range", + "port-block-allocation"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "type": module.params["type"], + "startip": module.params["startip"], + "source-startip": module.params["source_startip"], + "source-endip": module.params["source_endip"], + "permit-any-host": module.params["permit_any_host"], + "pba-timeout": module.params["pba_timeout"], + "num-blocks-per-user": module.params["num_blocks_per_user"], + "name": module.params["name"], + "endip": module.params["endip"], + "comments": module.params["comments"], + "block-size": module.params["block_size"], + "associated-interface": module.params["associated_interface"], + "arp-reply": module.params["arp_reply"], + "arp-intf": module.params["arp_intf"], + "dynamic_mapping": { + "arp-intf": module.params["dynamic_mapping_arp_intf"], + "arp-reply": module.params["dynamic_mapping_arp_reply"], + "associated-interface": module.params["dynamic_mapping_associated_interface"], + "block-size": module.params["dynamic_mapping_block_size"], + "comments": module.params["dynamic_mapping_comments"], + "endip": module.params["dynamic_mapping_endip"], + "num-blocks-per-user": module.params["dynamic_mapping_num_blocks_per_user"], + "pba-timeout": module.params["dynamic_mapping_pba_timeout"], + "permit-any-host": module.params["dynamic_mapping_permit_any_host"], + "source-endip": module.params["dynamic_mapping_source_endip"], + "source-startip": module.params["dynamic_mapping_source_startip"], + "startip": module.params["dynamic_mapping_startip"], + "type": module.params["dynamic_mapping_type"], + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['dynamic_mapping'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + # UPDATE THE CHANGED PARAMGRAM + module.paramgram = paramgram + + results = DEFAULT_RESULT_OBJ + try: + results = fmgr_fwobj_ippool_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py new file mode 100644 index 000000000..15e8977fa --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py @@ -0,0 +1,223 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwobj_ippool6 +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Allows the editing of IP Pool Objects within FortiManager. +description: + - Allows users to add/edit/delete IPv6 Pool Objects. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + startip: + description: + - First IPv6 address (inclusive) in the range for the address pool. + required: false + + name: + description: + - IPv6 IP pool name. + required: false + + endip: + description: + - Final IPv6 address (inclusive) in the range for the address pool. + required: false + + comments: + description: + - Comment. + required: false + + dynamic_mapping: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + dynamic_mapping_comments: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_endip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + dynamic_mapping_startip: + description: + - Dynamic Mapping clone of original suffixed parameter. + required: false + + +''' + +EXAMPLES = ''' +- name: ADD FMGR_FIREWALL_IPPOOL6 + fmgr_firewall_ippool6: + mode: "add" + adom: "ansible" + startip: + name: "IPv6 IPPool" + endip: + comments: "Created by Ansible" + +- name: DELETE FMGR_FIREWALL_IPPOOL6 + fmgr_firewall_ippool6: + mode: "delete" + adom: "ansible" + name: "IPv6 IPPool" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +def fmgr_fwobj_ippool6_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/firewall/ippool6'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/ippool6/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + startip=dict(required=False, type="str"), + name=dict(required=False, type="str"), + endip=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + dynamic_mapping=dict(required=False, type="list"), + dynamic_mapping_comments=dict(required=False, type="str"), + dynamic_mapping_endip=dict(required=False, type="str"), + dynamic_mapping_startip=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "startip": module.params["startip"], + "name": module.params["name"], + "endip": module.params["endip"], + "comments": module.params["comments"], + "dynamic_mapping": { + "comments": module.params["dynamic_mapping_comments"], + "endip": module.params["dynamic_mapping_endip"], + "startip": module.params["dynamic_mapping_startip"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['dynamic_mapping'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_fwobj_ippool6_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py new file mode 100644 index 000000000..fb8a3597f --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py @@ -0,0 +1,617 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwobj_service +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manages FortiManager Firewall Service Objects. +description: + - Manages FortiManager Firewall Service Objects. + +options: + adom: + description: + -The ADOM the configuration should belong to. + required: false + default: root + + app_category: + description: + - Application category ID. + required: false + + app_service_type: + description: + - Application service type. + required: false + + application: + description: + - Application ID. + required: false + + category: + description: + - Service category. + required: false + + check_reset_range: + description: + - Enable disable RST check. + required: false + + color: + description: + - GUI icon color. + required: false + default: 22 + + comment: + description: + - Comment. + required: false + + custom_type: + description: + - Tells module what kind of custom service to be added. + choices: ['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp', 'connect', 'socks_tcp', 'socks_udp', 'all'] + default: all + required: false + + explicit_proxy: + description: + - Enable/disable explicit web proxy service. + choices: ['enable', 'disable'] + default: 'disable' + required: false + + fqdn: + description: + - Fully qualified domain name. + required: false + default: "" + + group_name: + description: + - Name of the Service Group. + required: false + + group_member: + description: + - Comma-Seperated list of members' names. + required: false + + icmp_code: + description: + - ICMP code. + required: false + + icmp_type: + description: + - ICMP type. + required: false + + iprange: + description: + - Start IP-End IP. + required: false + default: "0.0.0.0" + + name: + description: + - Custom service name. + required: false + + mode: + description: + - Sets one of three modes for managing the object. + choices: ['add', 'set', 'delete'] + default: add + required: false + + object_type: + description: + - Tells module if we are adding a custom service, category, or group. + choices: ['custom', 'group', 'category'] + required: false + + protocol: + description: + - Protocol type. + required: false + + protocol_number: + description: + - IP protocol number. + required: false + + sctp_portrange: + description: + - Multiple SCTP port ranges. Comma separated list of destination ports to add (i.e. '443,80'). + - Syntax is <destPort:sourcePort> + - If no sourcePort is defined, it assumes all of them. + - Ranges can be defined with a hyphen - + - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000). + - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000'). + required: false + + session_ttl: + description: + - Session TTL (300 - 604800, 0 = default). + required: false + default: 0 + + tcp_halfclose_timer: + description: + - TCP half close timeout (1 - 86400 sec, 0 = default). + required: false + default: 0 + + tcp_halfopen_timer: + description: + - TCP half close timeout (1 - 86400 sec, 0 = default). + required: false + default: 0 + + tcp_portrange: + description: + - Comma separated list of destination ports to add (i.e. '443,80'). + - Syntax is <destPort:sourcePort> + - If no sourcePort is defined, it assumes all of them. + - Ranges can be defined with a hyphen - + - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000). + - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000'). + required: false + + tcp_timewait_timer: + description: + - TCP half close timeout (1 - 300 sec, 0 = default). + required: false + default: 0 + + udp_idle_timer: + description: + - TCP half close timeout (0 - 86400 sec, 0 = default). + required: false + default: 0 + + udp_portrange: + description: + - Comma separated list of destination ports to add (i.e. '443,80'). + - Syntax is <destPort:sourcePort> + - If no sourcePort is defined, it assumes all of them. + - Ranges can be defined with a hyphen - + - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000). + - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000'). + required: false + + visibility: + description: + - Enable/disable service visibility. + required: false + choices: ["enable", "disable"] + default: "enable" + +''' + +EXAMPLES = ''' +- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_service" + object_type: "custom" + custom_type: "tcp_udp_sctp" + tcp_portrange: "443" + udp_portrange: "51" + sctp_portrange: "100" + +- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP WITH SOURCE RANGES AND MULTIPLES + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_serviceWithSource" + object_type: "custom" + custom_type: "tcp_udp_sctp" + tcp_portrange: "443:2000-1000,80-82:10000-20000" + udp_portrange: "51:100-200,162:200-400" + sctp_portrange: "100:2000-2500" + +- name: ADD A CUSTOM SERVICE FOR ICMP + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_icmp" + object_type: "custom" + custom_type: "icmp" + icmp_type: "8" + icmp_code: "3" + +- name: ADD A CUSTOM SERVICE FOR ICMP6 + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_icmp6" + object_type: "custom" + custom_type: "icmp6" + icmp_type: "5" + icmp_code: "1" + +- name: ADD A CUSTOM SERVICE FOR IP - GRE + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_icmp6" + object_type: "custom" + custom_type: "ip" + protocol_number: "47" + +- name: ADD A CUSTOM PROXY FOR ALL WITH SOURCE RANGES AND MULTIPLES + community.fortios.fmgr_fwobj_service: + adom: "ansible" + name: "ansible_custom_proxy_all" + object_type: "custom" + custom_type: "all" + explicit_proxy: "enable" + tcp_portrange: "443:2000-1000,80-82:10000-20000" + iprange: "www.ansible.com" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +def fmgr_fwobj_service_custom(fmgr, paramgram): + """ + description: + - the tcp and udp-portrange parameters are in a list when there are multiple. they are not in a list when they + singular or by themselves (only 1 was listed) + - the syntax for this is (destPort:sourcePort). Ranges are (xxxx-xxxx) i.e. 443:443, or 443:1000-2000. + - if you leave out the second field after the colon (source port) it assumes any source port (which is usual) + - multiples would look like ['443:1000-2000','80'] + - a single would look simple like "443:1000-2000" without the list around it ( a string!) + - the protocol parameter is the protocol NUMBER, not the string of it. + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add']: + # SET THE URL FOR ADD / SET + url = '/pm/config/adom/{adom}/obj/firewall/service/custom'.format(adom=paramgram["adom"]) + # BUILD THE DEFAULT DATAGRAM + datagram = { + # ADVANCED OPTIONS + "app-category": paramgram["app-category"], + "app-service-type": paramgram["app-service-type"], + "application": paramgram["application"], + "category": paramgram["category"], + "check-reset-range": paramgram["check-reset-range"], + "color": paramgram["color"], + "session-ttl": paramgram["session-ttl"], + "tcp-halfclose-timer": paramgram["tcp-halfclose-timer"], + "tcp-halfopen-timer": paramgram["tcp-halfopen-timer"], + "tcp-timewait-timer": paramgram["tcp-timewait-timer"], + "udp-idle-timer": paramgram["udp-idle-timer"], + "visibility": paramgram["visibility"], + "comment": paramgram["comment"], + "proxy": paramgram["explicit-proxy"], + "name": paramgram["name"] + } + + if datagram["proxy"] == "disable": + ####################################### + # object-type = "TCP/UDP/SCTP" + ####################################### + if paramgram["custom_type"] == "tcp_udp_sctp": + datagram["protocol"] = "TCP/UDP/SCTP" + # PROCESS PORT RANGES TO PUT INTO THE PROPER SYNTAX + if paramgram["tcp-portrange"] is not None: + tcp_list = [] + for tcp in paramgram["tcp-portrange"].split(","): + tcp = tcp.strip() + tcp_list.append(tcp) + datagram["tcp-portrange"] = tcp_list + + if paramgram["udp-portrange"] is not None: + udp_list = [] + for udp in paramgram["udp-portrange"].split(","): + udp = udp.strip() + udp_list.append(udp) + datagram["udp-portrange"] = udp_list + + if paramgram["sctp-portrange"] is not None: + sctp_list = [] + for sctp in paramgram["sctp-portrange"].split(","): + sctp = sctp.strip() + sctp_list.append(sctp) + datagram["sctp-portrange"] = sctp_list + + ####################################### + # object-type = "ICMP" + ####################################### + if paramgram["custom_type"] == "icmp": + datagram["icmpcode"] = paramgram["icmp_code"] + datagram["icmptype"] = paramgram["icmp_type"] + datagram["protocol"] = "ICMP" + + ####################################### + # object-type = "ICMP6" + ####################################### + if paramgram["custom_type"] == "icmp6": + datagram["icmpcode"] = paramgram["icmp_code"] + datagram["icmptype"] = paramgram["icmp_type"] + datagram["protocol"] = "ICMP6" + + ####################################### + # object-type = "IP" + ####################################### + if paramgram["custom_type"] == "ip": + datagram["protocol"] = "IP" + datagram["protocol-number"] = paramgram["protocol-number"] + + ####################################### + # object-type in any of the explicit proxy options + ####################################### + if datagram["proxy"] == "enable": + datagram["protocol"] = paramgram["custom_type"].upper() + datagram["iprange"] = paramgram["iprange"] + + # PROCESS PROXY TCP PORT RANGES TO PUT INTO THE PROPER SYNTAX + if paramgram["tcp-portrange"] is not None: + tcp_list = [] + for tcp in paramgram["tcp-portrange"].split(","): + tcp = tcp.strip() + tcp_list.append(tcp) + datagram["tcp-portrange"] = tcp_list + + if paramgram["mode"] == "delete": + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/config/adom/{adom}/obj/firewall/service/custom' \ + '/{name}'.format(adom=paramgram["adom"], name=paramgram["name"]) + + datagram = scrub_dict(datagram) + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwobj_service_group(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add']: + url = '/pm/config/adom/{adom}/obj/firewall/service/group'.format(adom=paramgram["adom"]) + datagram = { + "name": paramgram["group-name"], + "comment": paramgram["comment"], + "proxy": paramgram["explicit-proxy"], + "color": paramgram["color"] + } + + members = paramgram["group-member"] + member = [] + for obj in members.split(","): + member.append(obj.strip()) + datagram["member"] = member + + if paramgram["mode"] == "delete": + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/config/adom/{adom}/obj/firewall/service/group' \ + '/{name}'.format(adom=paramgram["adom"], name=paramgram["group-name"]) + + datagram = scrub_dict(datagram) + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwobj_service_category(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + response = DEFAULT_RESULT_OBJ + if paramgram["mode"] in ['set', 'add']: + url = '/pm/config/adom/{adom}/obj/firewall/service/category'.format(adom=paramgram["adom"]) + # GET RID OF ANY WHITESPACE + category = paramgram["category"] + category = category.strip() + + datagram = { + "name": paramgram["category"], + "comment": "Created by Ansible" + } + + # IF MODE = DELETE + if paramgram["mode"] == "delete": + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/config/adom/{adom}/obj/firewall/service/category' \ + '/{name}'.format(adom=paramgram["adom"], name=paramgram["category"]) + + datagram = scrub_dict(datagram) + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(required=False, type="str", choices=['add', 'set', 'delete'], default="add"), + app_category=dict(required=False, type="str"), + app_service_type=dict(required=False, type="str"), + application=dict(required=False, type="str"), + category=dict(required=False, type="str"), + check_reset_range=dict(required=False, type="str"), + color=dict(required=False, type="int", default=22), + comment=dict(required=False, type="str"), + custom_type=dict(required=False, type="str", choices=['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp', + 'connect', 'socks_tcp', 'socks_udp', 'all'], + default="all"), + explicit_proxy=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"), + fqdn=dict(required=False, type="str", default=""), + group_name=dict(required=False, type="str"), + group_member=dict(required=False, type="str"), + icmp_code=dict(required=False, type="int"), + icmp_type=dict(required=False, type="int"), + iprange=dict(required=False, type="str", default="0.0.0.0"), + name=dict(required=False, type="str"), + protocol=dict(required=False, type="str"), + protocol_number=dict(required=False, type="int"), + sctp_portrange=dict(required=False, type="str"), + session_ttl=dict(required=False, type="int", default=0), + object_type=dict(required=False, type="str", choices=['custom', 'group', 'category']), + tcp_halfclose_timer=dict(required=False, type="int", default=0), + tcp_halfopen_timer=dict(required=False, type="int", default=0), + tcp_portrange=dict(required=False, type="str"), + tcp_timewait_timer=dict(required=False, type="int", default=0), + udp_idle_timer=dict(required=False, type="int", default=0), + udp_portrange=dict(required=False, type="str"), + visibility=dict(required=False, type="str", default="enable", choices=["enable", "disable"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE DATAGRAM + paramgram = { + "adom": module.params["adom"], + "app-category": module.params["app_category"], + "app-service-type": module.params["app_service_type"], + "application": module.params["application"], + "category": module.params["category"], + "check-reset-range": module.params["check_reset_range"], + "color": module.params["color"], + "comment": module.params["comment"], + "custom_type": module.params["custom_type"], + "explicit-proxy": module.params["explicit_proxy"], + "fqdn": module.params["fqdn"], + "group-name": module.params["group_name"], + "group-member": module.params["group_member"], + "icmp_code": module.params["icmp_code"], + "icmp_type": module.params["icmp_type"], + "iprange": module.params["iprange"], + "name": module.params["name"], + "mode": module.params["mode"], + "protocol": module.params["protocol"], + "protocol-number": module.params["protocol_number"], + "sctp-portrange": module.params["sctp_portrange"], + "object_type": module.params["object_type"], + "session-ttl": module.params["session_ttl"], + "tcp-halfclose-timer": module.params["tcp_halfclose_timer"], + "tcp-halfopen-timer": module.params["tcp_halfopen_timer"], + "tcp-portrange": module.params["tcp_portrange"], + "tcp-timewait-timer": module.params["tcp_timewait_timer"], + "udp-idle-timer": module.params["udp_idle_timer"], + "udp-portrange": module.params["udp_portrange"], + "visibility": module.params["visibility"], + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + + try: + # CHECK FOR CATEGORIES TO ADD + # THIS IS ONLY WHEN OBJECT_TYPE ISN'T SPECIFICALLY ADDING A CATEGORY! + # WE NEED TO ADD THE CATEGORY BEFORE ADDING THE OBJECT + # IF ANY category ARE DEFINED AND MODE IS ADD OR SET LETS ADD THOSE + # THIS IS A "BLIND ADD" AND THE EXIT CODE FOR OBJECT ALREADY EXISTS IS TREATED AS A PASS + if paramgram["category"] is not None and paramgram["mode"] in ['add', 'set'] \ + and paramgram["object_type"] != "category": + category_add = fmgr_fwobj_service_category(fmgr, paramgram) + fmgr.govern_response(module=module, results=category_add, + ansible_facts=fmgr.construct_ansible_facts(category_add, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT_TYPE IS CATEGORY... + if paramgram["object_type"] == 'category': + results = fmgr_fwobj_service_category(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT_TYPE IS CUSTOM... + if paramgram["object_type"] == 'custom': + results = fmgr_fwobj_service_custom(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT_TYPE IS GROUP... + if paramgram["object_type"] == 'group': + results = fmgr_fwobj_service_group(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py new file mode 100644 index 000000000..adba2e495 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py @@ -0,0 +1,2424 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwobj_vip +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manages Virtual IPs objects in FortiManager +description: + - Manages Virtual IP objects in FortiManager for IPv4 + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + websphere_server: + description: + - Enable to add an HTTP header to indicate SSL offloading for a WebSphere server. + - choice | disable | Do not add HTTP header indicating SSL offload for WebSphere server. + - choice | enable | Add HTTP header indicating SSL offload for WebSphere server. + required: false + choices: ["disable", "enable"] + + weblogic_server: + description: + - Enable to add an HTTP header to indicate SSL offloading for a WebLogic server. + - choice | disable | Do not add HTTP header indicating SSL offload for WebLogic server. + - choice | enable | Add HTTP header indicating SSL offload for WebLogic server. + required: false + choices: ["disable", "enable"] + + type: + description: + - Configure a static NAT, load balance, server load balance, DNS translation, or FQDN VIP. + - choice | static-nat | Static NAT. + - choice | load-balance | Load balance. + - choice | server-load-balance | Server load balance. + - choice | dns-translation | DNS translation. + - choice | fqdn | FQDN Translation + required: false + choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"] + + ssl_server_session_state_type: + description: + - How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate. + - choice | disable | Do not keep session states. + - choice | time | Expire session states after this many minutes. + - choice | count | Expire session states when this maximum is reached. + - choice | both | Expire session states based on time or count, whichever occurs first. + required: false + choices: ["disable", "time", "count", "both"] + + ssl_server_session_state_timeout: + description: + - Number of minutes to keep FortiGate to Server SSL session state. + required: false + + ssl_server_session_state_max: + description: + - Maximum number of FortiGate to Server SSL session states to keep. + required: false + + ssl_server_min_version: + description: + - Lowest SSL/TLS version acceptable from a server. Use the client setting by default. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + - choice | client | Use same value as client configuration. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"] + + ssl_server_max_version: + description: + - Highest SSL/TLS version acceptable from a server. Use the client setting by default. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + - choice | client | Use same value as client configuration. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"] + + ssl_server_algorithm: + description: + - Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength + - choice | high | High encryption. Allow only AES and ChaCha. + - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES. + - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4. + - choice | custom | Custom encryption. Use ssl-server-cipher-suites to select the cipher suites that are allowed. + - choice | client | Use the same encryption algorithms for both client and server sessions. + required: false + choices: ["high", "low", "medium", "custom", "client"] + + ssl_send_empty_frags: + description: + - Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 & TLS 1.0 only). + - choice | disable | Do not send empty fragments. + - choice | enable | Send empty fragments. + required: false + choices: ["disable", "enable"] + + ssl_pfs: + description: + - Select the cipher suites that can be used for SSL perfect forward secrecy (PFS). + - choice | require | Allow only Diffie-Hellman cipher-suites, so PFS is applied. + - choice | deny | Allow only non-Diffie-Hellman cipher-suites, so PFS is not applied. + - choice | allow | Allow use of any cipher suite so PFS may or may not be used depending on the cipher suite + required: false + choices: ["require", "deny", "allow"] + + ssl_mode: + description: + - Apply SSL offloading mode + - choice | half | Client to FortiGate SSL. + - choice | full | Client to FortiGate and FortiGate to Server SSL. + required: false + choices: ["half", "full"] + + ssl_min_version: + description: + - Lowest SSL/TLS version acceptable from a client. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + ssl_max_version: + description: + - Highest SSL/TLS version acceptable from a client. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + ssl_http_match_host: + description: + - Enable/disable HTTP host matching for location conversion. + - choice | disable | Do not match HTTP host. + - choice | enable | Match HTTP host in response header. + required: false + choices: ["disable", "enable"] + + ssl_http_location_conversion: + description: + - Enable to replace HTTP with HTTPS in the reply's Location HTTP header field. + - choice | disable | Disable HTTP location conversion. + - choice | enable | Enable HTTP location conversion. + required: false + choices: ["disable", "enable"] + + ssl_hsts_include_subdomains: + description: + - Indicate that HSTS header applies to all subdomains. + - choice | disable | HSTS header does not apply to subdomains. + - choice | enable | HSTS header applies to subdomains. + required: false + choices: ["disable", "enable"] + + ssl_hsts_age: + description: + - Number of seconds the client should honour the HSTS setting. + required: false + + ssl_hsts: + description: + - Enable/disable including HSTS header in response. + - choice | disable | Do not add a HSTS header to each a HTTP response. + - choice | enable | Add a HSTS header to each HTTP response. + required: false + choices: ["disable", "enable"] + + ssl_hpkp_report_uri: + description: + - URL to report HPKP violations to. + required: false + + ssl_hpkp_primary: + description: + - Certificate to generate primary HPKP pin from. + required: false + + ssl_hpkp_include_subdomains: + description: + - Indicate that HPKP header applies to all subdomains. + - choice | disable | HPKP header does not apply to subdomains. + - choice | enable | HPKP header applies to subdomains. + required: false + choices: ["disable", "enable"] + + ssl_hpkp_backup: + description: + - Certificate to generate backup HPKP pin from. + required: false + + ssl_hpkp_age: + description: + - Number of seconds the client should honour the HPKP setting. + required: false + + ssl_hpkp: + description: + - Enable/disable including HPKP header in response. + - choice | disable | Do not add a HPKP header to each HTTP response. + - choice | enable | Add a HPKP header to each a HTTP response. + - choice | report-only | Add a HPKP Report-Only header to each HTTP response. + required: false + choices: ["disable", "enable", "report-only"] + + ssl_dh_bits: + description: + - Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions. + - choice | 768 | 768-bit Diffie-Hellman prime. + - choice | 1024 | 1024-bit Diffie-Hellman prime. + - choice | 1536 | 1536-bit Diffie-Hellman prime. + - choice | 2048 | 2048-bit Diffie-Hellman prime. + - choice | 3072 | 3072-bit Diffie-Hellman prime. + - choice | 4096 | 4096-bit Diffie-Hellman prime. + required: false + choices: ["768", "1024", "1536", "2048", "3072", "4096"] + + ssl_client_session_state_type: + description: + - How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate. + - choice | disable | Do not keep session states. + - choice | time | Expire session states after this many minutes. + - choice | count | Expire session states when this maximum is reached. + - choice | both | Expire session states based on time or count, whichever occurs first. + required: false + choices: ["disable", "time", "count", "both"] + + ssl_client_session_state_timeout: + description: + - Number of minutes to keep client to FortiGate SSL session state. + required: false + + ssl_client_session_state_max: + description: + - Maximum number of client to FortiGate SSL session states to keep. + required: false + + ssl_client_renegotiation: + description: + - Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746. + - choice | deny | Abort any client initiated SSL re-negotiation attempt. + - choice | allow | Allow a SSL client to renegotiate. + - choice | secure | Abort any client initiated SSL re-negotiation attempt that does not use RFC 5746. + required: false + choices: ["deny", "allow", "secure"] + + ssl_client_fallback: + description: + - Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507). + - choice | disable | Disable. + - choice | enable | Enable. + required: false + choices: ["disable", "enable"] + + ssl_certificate: + description: + - The name of the SSL certificate to use for SSL acceleration. + required: false + + ssl_algorithm: + description: + - Permitted encryption algorithms for SSL sessions according to encryption strength. + - choice | high | High encryption. Allow only AES and ChaCha. + - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4. + - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES. + - choice | custom | Custom encryption. Use config ssl-cipher-suites to select the cipher suites that are allowed. + required: false + choices: ["high", "medium", "low", "custom"] + + srcintf_filter: + description: + - Interfaces to which the VIP applies. Separate the names with spaces. + required: false + + src_filter: + description: + - Source address filter. Each address must be either an IP/subnet (x.x.x.x/n) or a range (x.x.x.x-y.y.y.y). + - Separate addresses with spaces. + required: false + + service: + description: + - Service name. + required: false + + server_type: + description: + - Protocol to be load balanced by the virtual server (also called the server load balance virtual IP). + - choice | http | HTTP + - choice | https | HTTPS + - choice | ssl | SSL + - choice | tcp | TCP + - choice | udp | UDP + - choice | ip | IP + - choice | imaps | IMAPS + - choice | pop3s | POP3S + - choice | smtps | SMTPS + required: false + choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"] + + protocol: + description: + - Protocol to use when forwarding packets. + - choice | tcp | TCP. + - choice | udp | UDP. + - choice | sctp | SCTP. + - choice | icmp | ICMP. + required: false + choices: ["tcp", "udp", "sctp", "icmp"] + + portmapping_type: + description: + - Port mapping type. + - choice | 1-to-1 | One to one. + - choice | m-to-n | Many to many. + required: false + choices: ["1-to-1", "m-to-n"] + + portforward: + description: + - Enable/disable port forwarding. + - choice | disable | Disable port forward. + - choice | enable | Enable port forward. + required: false + choices: ["disable", "enable"] + + persistence: + description: + - Configure how to make sure that clients connect to the same server every time they make a request that is part + - of the same session. + - choice | none | None. + - choice | http-cookie | HTTP cookie. + - choice | ssl-session-id | SSL session ID. + required: false + choices: ["none", "http-cookie", "ssl-session-id"] + + outlook_web_access: + description: + - Enable to add the Front-End-Https header for Microsoft Outlook Web Access. + - choice | disable | Disable Outlook Web Access support. + - choice | enable | Enable Outlook Web Access support. + required: false + choices: ["disable", "enable"] + + nat_source_vip: + description: + - Enable to prevent unintended servers from using a virtual IP. + - Disable to use the actual IP address of the server as the source address. + - choice | disable | Do not force to NAT as VIP. + - choice | enable | Force to NAT as VIP. + required: false + choices: ["disable", "enable"] + + name: + description: + - Virtual IP name. + required: false + + monitor: + description: + - Name of the health check monitor to use when polling to determine a virtual server's connectivity status. + required: false + + max_embryonic_connections: + description: + - Maximum number of incomplete connections. + required: false + + mappedport: + description: + - Port number range on the destination network to which the external port number range is mapped. + required: false + + mappedip: + description: + - IP address or address range on the destination network to which the external IP address is mapped. + required: false + + mapped_addr: + description: + - Mapped FQDN address name. + required: false + + ldb_method: + description: + - Method used to distribute sessions to real servers. + - choice | static | Distribute to server based on source IP. + - choice | round-robin | Distribute to server based round robin order. + - choice | weighted | Distribute to server based on weight. + - choice | least-session | Distribute to server with lowest session count. + - choice | least-rtt | Distribute to server with lowest Round-Trip-Time. + - choice | first-alive | Distribute to the first server that is alive. + - choice | http-host | Distribute to server based on host field in HTTP header. + required: false + choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"] + + https_cookie_secure: + description: + - Enable/disable verification that inserted HTTPS cookies are secure. + - choice | disable | Do not mark cookie as secure, allow sharing between an HTTP and HTTPS connection. + - choice | enable | Mark inserted cookie as secure, cookie can only be used for HTTPS a connection. + required: false + choices: ["disable", "enable"] + + http_multiplex: + description: + - Enable/disable HTTP multiplexing. + - choice | disable | Disable HTTP session multiplexing. + - choice | enable | Enable HTTP session multiplexing. + required: false + choices: ["disable", "enable"] + + http_ip_header_name: + description: + - For HTTP multiplexing, enter a custom HTTPS header name. The orig client IP address is added to this header. + - If empty, X-Forwarded-For is used. + required: false + + http_ip_header: + description: + - For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header. + - choice | disable | Disable adding HTTP header. + - choice | enable | Enable adding HTTP header. + required: false + choices: ["disable", "enable"] + + http_cookie_share: + description: + - Control sharing of cookies across virtual servers. same-ip means a cookie from one virtual server can be used + - by another. Disable stops cookie sharing. + - choice | disable | Only allow HTTP cookie to match this virtual server. + - choice | same-ip | Allow HTTP cookie to match any virtual server with same IP. + required: false + choices: ["disable", "same-ip"] + + http_cookie_path: + description: + - Limit HTTP cookie persistence to the specified path. + required: false + + http_cookie_generation: + description: + - Generation of HTTP cookie to be accepted. Changing invalidates all existing cookies. + required: false + + http_cookie_domain_from_host: + description: + - Enable/disable use of HTTP cookie domain from host field in HTTP. + - choice | disable | Disable use of HTTP cookie domain from host field in HTTP (use http-cooke-domain setting). + - choice | enable | Enable use of HTTP cookie domain from host field in HTTP. + required: false + choices: ["disable", "enable"] + + http_cookie_domain: + description: + - Domain that HTTP cookie persistence should apply to. + required: false + + http_cookie_age: + description: + - Time in minutes that client web browsers should keep a cookie. Default is 60 seconds. 0 = no time limit. + required: false + + gratuitous_arp_interval: + description: + - Enable to have the VIP send gratuitous ARPs. 0=disabled. Set from 5 up to 8640000 seconds to enable. + required: false + + extport: + description: + - Incoming port number range that you want to map to a port number range on the destination network. + required: false + + extip: + description: + - IP address or address range on the external interface that you want to map to an address or address range on t + - he destination network. + required: false + + extintf: + description: + - Interface connected to the source network that receives the packets that will be forwarded to the destination + - network. + required: false + + extaddr: + description: + - External FQDN address name. + required: false + + dns_mapping_ttl: + description: + - DNS mapping TTL (Set to zero to use TTL in DNS response, default = 0). + required: false + + comment: + description: + - Comment. + required: false + + color: + description: + - Color of icon on the GUI. + required: false + + arp_reply: + description: + - Enable to respond to ARP requests for this virtual IP address. Enabled by default. + - choice | disable | Disable ARP reply. + - choice | enable | Enable ARP reply. + required: false + choices: ["disable", "enable"] + + dynamic_mapping: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + dynamic_mapping_arp_reply: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_color: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_comment: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_dns_mapping_ttl: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_extaddr: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_extintf: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_extip: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_extport: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_gratuitous_arp_interval: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_cookie_age: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_cookie_domain: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_cookie_domain_from_host: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_http_cookie_generation: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_cookie_path: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_cookie_share: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | same-ip | + required: false + choices: ["disable", "same-ip"] + + dynamic_mapping_http_ip_header: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_http_ip_header_name: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_http_multiplex: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_https_cookie_secure: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ldb_method: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | static | + - choice | round-robin | + - choice | weighted | + - choice | least-session | + - choice | least-rtt | + - choice | first-alive | + - choice | http-host | + required: false + choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"] + + dynamic_mapping_mapped_addr: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_mappedip: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_mappedport: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_max_embryonic_connections: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_monitor: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_nat_source_vip: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_outlook_web_access: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_persistence: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | none | + - choice | http-cookie | + - choice | ssl-session-id | + required: false + choices: ["none", "http-cookie", "ssl-session-id"] + + dynamic_mapping_portforward: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_portmapping_type: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | 1-to-1 | + - choice | m-to-n | + required: false + choices: ["1-to-1", "m-to-n"] + + dynamic_mapping_protocol: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | tcp | + - choice | udp | + - choice | sctp | + - choice | icmp | + required: false + choices: ["tcp", "udp", "sctp", "icmp"] + + dynamic_mapping_server_type: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | http | + - choice | https | + - choice | ssl | + - choice | tcp | + - choice | udp | + - choice | ip | + - choice | imaps | + - choice | pop3s | + - choice | smtps | + required: false + choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"] + + dynamic_mapping_service: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_src_filter: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_srcintf_filter: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_algorithm: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | high | + - choice | medium | + - choice | low | + - choice | custom | + required: false + choices: ["high", "medium", "low", "custom"] + + dynamic_mapping_ssl_certificate: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_client_fallback: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_client_renegotiation: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | deny | + - choice | allow | + - choice | secure | + required: false + choices: ["deny", "allow", "secure"] + + dynamic_mapping_ssl_client_session_state_max: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_client_session_state_timeout: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_client_session_state_type: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | time | + - choice | count | + - choice | both | + required: false + choices: ["disable", "time", "count", "both"] + + dynamic_mapping_ssl_dh_bits: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | 768 | + - choice | 1024 | + - choice | 1536 | + - choice | 2048 | + - choice | 3072 | + - choice | 4096 | + required: false + choices: ["768", "1024", "1536", "2048", "3072", "4096"] + + dynamic_mapping_ssl_hpkp: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + - choice | report-only | + required: false + choices: ["disable", "enable", "report-only"] + + dynamic_mapping_ssl_hpkp_age: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_hpkp_backup: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_hpkp_include_subdomains: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_hpkp_primary: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_hpkp_report_uri: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_hsts: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_hsts_age: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_hsts_include_subdomains: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_http_location_conversion: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_http_match_host: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_max_version: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | ssl-3.0 | + - choice | tls-1.0 | + - choice | tls-1.1 | + - choice | tls-1.2 | + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + dynamic_mapping_ssl_min_version: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | ssl-3.0 | + - choice | tls-1.0 | + - choice | tls-1.1 | + - choice | tls-1.2 | + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + dynamic_mapping_ssl_mode: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | half | + - choice | full | + required: false + choices: ["half", "full"] + + dynamic_mapping_ssl_pfs: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | require | + - choice | deny | + - choice | allow | + required: false + choices: ["require", "deny", "allow"] + + dynamic_mapping_ssl_send_empty_frags: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_ssl_server_algorithm: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | high | + - choice | low | + - choice | medium | + - choice | custom | + - choice | client | + required: false + choices: ["high", "low", "medium", "custom", "client"] + + dynamic_mapping_ssl_server_max_version: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | ssl-3.0 | + - choice | tls-1.0 | + - choice | tls-1.1 | + - choice | tls-1.2 | + - choice | client | + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"] + + dynamic_mapping_ssl_server_min_version: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | ssl-3.0 | + - choice | tls-1.0 | + - choice | tls-1.1 | + - choice | tls-1.2 | + - choice | client | + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"] + + dynamic_mapping_ssl_server_session_state_max: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_server_session_state_timeout: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_server_session_state_type: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | time | + - choice | count | + - choice | both | + required: false + choices: ["disable", "time", "count", "both"] + + dynamic_mapping_type: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | static-nat | + - choice | load-balance | + - choice | server-load-balance | + - choice | dns-translation | + - choice | fqdn | + required: false + choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"] + + dynamic_mapping_weblogic_server: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_websphere_server: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + required: false + choices: ["disable", "enable"] + + dynamic_mapping_realservers_client_ip: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_healthcheck: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | disable | + - choice | enable | + - choice | vip | + required: false + choices: ["disable", "enable", "vip"] + + dynamic_mapping_realservers_holddown_interval: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_http_host: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_ip: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_max_connections: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_monitor: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_port: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_seq: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_realservers_status: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | active | + - choice | standby | + - choice | disable | + required: false + choices: ["active", "standby", "disable"] + + dynamic_mapping_realservers_weight: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + required: false + + dynamic_mapping_ssl_cipher_suites_cipher: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - choice | TLS-RSA-WITH-RC4-128-MD5 | + - choice | TLS-RSA-WITH-RC4-128-SHA | + - choice | TLS-RSA-WITH-DES-CBC-SHA | + - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | + - choice | TLS-RSA-WITH-AES-128-CBC-SHA | + - choice | TLS-RSA-WITH-AES-256-CBC-SHA | + - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | + - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | + - choice | TLS-RSA-WITH-SEED-CBC-SHA | + - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | + - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | + - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | + - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | + - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | + - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | + - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | + - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | + - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | + - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | + - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | + - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | + - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | + - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | + - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | + - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | + - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | + - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | + - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | + - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | + - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | + - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | + - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | + - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | + - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | + required: false + choices: ["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"] + + dynamic_mapping_ssl_cipher_suites_versions: + description: + - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent. + - FLAG Based Options. Specify multiple in list form. + - flag | ssl-3.0 | + - flag | tls-1.0 | + - flag | tls-1.1 | + - flag | tls-1.2 | + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + realservers: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + realservers_client_ip: + description: + - Only clients in this IP range can connect to this real server. + required: false + + realservers_healthcheck: + description: + - Enable to check the responsiveness of the real server before forwarding traffic. + - choice | disable | Disable per server health check. + - choice | enable | Enable per server health check. + - choice | vip | Use health check defined in VIP. + required: false + choices: ["disable", "enable", "vip"] + + realservers_holddown_interval: + description: + - Time in seconds that the health check monitor monitors an unresponsive server that should be active. + required: false + + realservers_http_host: + description: + - HTTP server domain name in HTTP header. + required: false + + realservers_ip: + description: + - IP address of the real server. + required: false + + realservers_max_connections: + description: + - Max number of active connections that can be directed to the real server. When reached, sessions are sent to + - their real servers. + required: false + + realservers_monitor: + description: + - Name of the health check monitor to use when polling to determine a virtual server's connectivity status. + required: false + + realservers_port: + description: + - Port for communicating with the real server. Required if port forwarding is enabled. + required: false + + realservers_seq: + description: + - Real Server Sequence Number + required: false + + realservers_status: + description: + - Set the status of the real server to active so that it can accept traffic. + - Or on standby or disabled so no traffic is sent. + - choice | active | Server status active. + - choice | standby | Server status standby. + - choice | disable | Server status disable. + required: false + choices: ["active", "standby", "disable"] + + realservers_weight: + description: + - Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more + - connections. + required: false + + ssl_cipher_suites: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssl_cipher_suites_cipher: + description: + - Cipher suite name. + - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5. + - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA. + - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA. + - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256. + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA. + - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA. + - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384. + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384. + - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA. + required: false + choices: ["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"] + + ssl_cipher_suites_versions: + description: + - SSL/TLS versions that the cipher suite can be used with. + - FLAG Based Options. Specify multiple in list form. + - flag | ssl-3.0 | SSL 3.0. + - flag | tls-1.0 | TLS 1.0. + - flag | tls-1.1 | TLS 1.1. + - flag | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + ssl_server_cipher_suites: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssl_server_cipher_suites_cipher: + description: + - Cipher suite name. + - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5. + - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA. + - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA. + - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256. + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA. + - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA. + - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA. + - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA. + - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384. + - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256. + - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256. + - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384. + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256. + - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384. + - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA. + - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA. + required: false + choices: ["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"] + + ssl_server_cipher_suites_priority: + description: + - SSL/TLS cipher suites priority. + required: false + + ssl_server_cipher_suites_versions: + description: + - SSL/TLS versions that the cipher suite can be used with. + - FLAG Based Options. Specify multiple in list form. + - flag | ssl-3.0 | SSL 3.0. + - flag | tls-1.0 | TLS 1.0. + - flag | tls-1.1 | TLS 1.1. + - flag | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + +''' + +EXAMPLES = ''' +# BASIC FULL STATIC NAT MAPPING +- name: EDIT FMGR_FIREWALL_VIP SNAT + community.fortios.fmgr_fwobj_vip: + name: "Basic StaticNAT Map" + mode: "set" + adom: "ansible" + type: "static-nat" + extip: "82.72.192.185" + extintf: "any" + mappedip: "10.7.220.25" + comment: "Created by Ansible" + color: "17" + +# BASIC PORT PNAT MAPPING +- name: EDIT FMGR_FIREWALL_VIP PNAT + community.fortios.fmgr_fwobj_vip: + name: "Basic PNAT Map Port 10443" + mode: "set" + adom: "ansible" + type: "static-nat" + extip: "82.72.192.185" + extport: "10443" + extintf: "any" + portforward: "enable" + protocol: "tcp" + mappedip: "10.7.220.25" + mappedport: "443" + comment: "Created by Ansible" + color: "17" + +# BASIC DNS TRANSLATION NAT +- name: EDIT FMGR_FIREWALL_DNST + community.fortios.fmgr_fwobj_vip: + name: "Basic DNS Translation" + mode: "set" + adom: "ansible" + type: "dns-translation" + extip: "192.168.0.1-192.168.0.100" + extintf: "dmz" + mappedip: "3.3.3.0/24, 4.0.0.0/24" + comment: "Created by Ansible" + color: "12" + +# BASIC FQDN NAT +- name: EDIT FMGR_FIREWALL_FQDN + community.fortios.fmgr_fwobj_vip: + name: "Basic FQDN Translation" + mode: "set" + adom: "ansible" + type: "fqdn" + mapped_addr: "google-play" + comment: "Created by Ansible" + color: "5" + +# DELETE AN ENTRY +- name: DELETE FMGR_FIREWALL_VIP PNAT + community.fortios.fmgr_fwobj_vip: + name: "Basic PNAT Map Port 10443" + mode: "delete" + adom: "ansible" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +def fmgr_firewall_vip_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/firewall/vip'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/vip/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + websphere_server=dict(required=False, type="str", choices=["disable", "enable"]), + weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]), + type=dict(required=False, type="str", + choices=["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]), + ssl_server_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]), + ssl_server_session_state_timeout=dict(required=False, type="int"), + ssl_server_session_state_max=dict(required=False, type="int"), + ssl_server_min_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]), + ssl_server_max_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]), + ssl_server_algorithm=dict(required=False, type="str", choices=["high", "low", "medium", "custom", "client"]), + ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]), + ssl_mode=dict(required=False, type="str", choices=["half", "full"]), + ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_hsts_age=dict(required=False, type="int"), + ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_hpkp_report_uri=dict(required=False, type="str"), + ssl_hpkp_primary=dict(required=False, type="str"), + ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_hpkp_backup=dict(required=False, type="str"), + ssl_hpkp_age=dict(required=False, type="int"), + ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]), + ssl_dh_bits=dict(required=False, type="str", choices=["768", "1024", "1536", "2048", "3072", "4096"]), + ssl_client_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]), + ssl_client_session_state_timeout=dict(required=False, type="int"), + ssl_client_session_state_max=dict(required=False, type="int"), + ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]), + ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_certificate=dict(required=False, type="str"), + ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]), + srcintf_filter=dict(required=False, type="str"), + src_filter=dict(required=False, type="str"), + service=dict(required=False, type="str"), + server_type=dict(required=False, type="str", + choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]), + protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]), + portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]), + portforward=dict(required=False, type="str", choices=["disable", "enable"]), + persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]), + outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]), + nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]), + name=dict(required=False, type="str"), + monitor=dict(required=False, type="str"), + max_embryonic_connections=dict(required=False, type="int"), + mappedport=dict(required=False, type="str"), + mappedip=dict(required=False, type="str"), + mapped_addr=dict(required=False, type="str"), + ldb_method=dict(required=False, type="str", + choices=["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", + "http-host"]), + https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]), + http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]), + http_ip_header_name=dict(required=False, type="str"), + http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]), + http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]), + http_cookie_path=dict(required=False, type="str"), + http_cookie_generation=dict(required=False, type="int"), + http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]), + http_cookie_domain=dict(required=False, type="str"), + http_cookie_age=dict(required=False, type="int"), + gratuitous_arp_interval=dict(required=False, type="int"), + extport=dict(required=False, type="str"), + extip=dict(required=False, type="str"), + extintf=dict(required=False, type="str"), + extaddr=dict(required=False, type="str"), + dns_mapping_ttl=dict(required=False, type="int"), + comment=dict(required=False, type="str"), + color=dict(required=False, type="int"), + arp_reply=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping=dict(required=False, type="list"), + dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_color=dict(required=False, type="int"), + dynamic_mapping_comment=dict(required=False, type="str"), + dynamic_mapping_dns_mapping_ttl=dict(required=False, type="int"), + dynamic_mapping_extaddr=dict(required=False, type="str"), + dynamic_mapping_extintf=dict(required=False, type="str"), + dynamic_mapping_extip=dict(required=False, type="str"), + dynamic_mapping_extport=dict(required=False, type="str"), + dynamic_mapping_gratuitous_arp_interval=dict(required=False, type="int"), + dynamic_mapping_http_cookie_age=dict(required=False, type="int"), + dynamic_mapping_http_cookie_domain=dict(required=False, type="str"), + dynamic_mapping_http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_http_cookie_generation=dict(required=False, type="int"), + dynamic_mapping_http_cookie_path=dict(required=False, type="str"), + dynamic_mapping_http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]), + dynamic_mapping_http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_http_ip_header_name=dict(required=False, type="str"), + dynamic_mapping_http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ldb_method=dict(required=False, type="str", choices=["static", + "round-robin", + "weighted", + "least-session", + "least-rtt", + "first-alive", + "http-host"]), + dynamic_mapping_mapped_addr=dict(required=False, type="str"), + dynamic_mapping_mappedip=dict(required=False, type="str"), + dynamic_mapping_mappedport=dict(required=False, type="str"), + dynamic_mapping_max_embryonic_connections=dict(required=False, type="int"), + dynamic_mapping_monitor=dict(required=False, type="str"), + dynamic_mapping_nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]), + dynamic_mapping_portforward=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]), + dynamic_mapping_protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]), + dynamic_mapping_server_type=dict(required=False, type="str", + choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", + "smtps"]), + dynamic_mapping_service=dict(required=False, type="str"), + dynamic_mapping_src_filter=dict(required=False, type="str"), + dynamic_mapping_srcintf_filter=dict(required=False, type="str"), + dynamic_mapping_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]), + dynamic_mapping_ssl_certificate=dict(required=False, type="str"), + dynamic_mapping_ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]), + dynamic_mapping_ssl_client_session_state_max=dict(required=False, type="int"), + dynamic_mapping_ssl_client_session_state_timeout=dict(required=False, type="int"), + dynamic_mapping_ssl_client_session_state_type=dict(required=False, type="str", + choices=["disable", "time", "count", "both"]), + dynamic_mapping_ssl_dh_bits=dict(required=False, type="str", + choices=["768", "1024", "1536", "2048", "3072", "4096"]), + dynamic_mapping_ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]), + dynamic_mapping_ssl_hpkp_age=dict(required=False, type="int"), + dynamic_mapping_ssl_hpkp_backup=dict(required=False, type="str"), + dynamic_mapping_ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_hpkp_primary=dict(required=False, type="str"), + dynamic_mapping_ssl_hpkp_report_uri=dict(required=False, type="str"), + dynamic_mapping_ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_hsts_age=dict(required=False, type="int"), + dynamic_mapping_ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_max_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + dynamic_mapping_ssl_min_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + dynamic_mapping_ssl_mode=dict(required=False, type="str", choices=["half", "full"]), + dynamic_mapping_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]), + dynamic_mapping_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_ssl_server_algorithm=dict(required=False, type="str", + choices=["high", "low", "medium", "custom", "client"]), + dynamic_mapping_ssl_server_max_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]), + dynamic_mapping_ssl_server_min_version=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]), + dynamic_mapping_ssl_server_session_state_max=dict(required=False, type="int"), + dynamic_mapping_ssl_server_session_state_timeout=dict(required=False, type="int"), + dynamic_mapping_ssl_server_session_state_type=dict(required=False, type="str", + choices=["disable", "time", "count", "both"]), + dynamic_mapping_type=dict(required=False, type="str", + choices=["static-nat", "load-balance", "server-load-balance", "dns-translation", + "fqdn"]), + dynamic_mapping_weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]), + dynamic_mapping_websphere_server=dict(required=False, type="str", choices=["disable", "enable"]), + + dynamic_mapping_realservers_client_ip=dict(required=False, type="str"), + dynamic_mapping_realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]), + dynamic_mapping_realservers_holddown_interval=dict(required=False, type="int"), + dynamic_mapping_realservers_http_host=dict(required=False, type="str"), + dynamic_mapping_realservers_ip=dict(required=False, type="str"), + dynamic_mapping_realservers_max_connections=dict(required=False, type="int"), + dynamic_mapping_realservers_monitor=dict(required=False, type="str"), + dynamic_mapping_realservers_port=dict(required=False, type="int"), + dynamic_mapping_realservers_seq=dict(required=False, type="str"), + dynamic_mapping_realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]), + dynamic_mapping_realservers_weight=dict(required=False, type="int"), + + dynamic_mapping_ssl_cipher_suites_cipher=dict(required=False, + type="str", + choices=["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"]), + dynamic_mapping_ssl_cipher_suites_versions=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + realservers=dict(required=False, type="list"), + realservers_client_ip=dict(required=False, type="str"), + realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]), + realservers_holddown_interval=dict(required=False, type="int"), + realservers_http_host=dict(required=False, type="str"), + realservers_ip=dict(required=False, type="str"), + realservers_max_connections=dict(required=False, type="int"), + realservers_monitor=dict(required=False, type="str"), + realservers_port=dict(required=False, type="int"), + realservers_seq=dict(required=False, type="str"), + realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]), + realservers_weight=dict(required=False, type="int"), + ssl_cipher_suites=dict(required=False, type="list"), + ssl_cipher_suites_cipher=dict(required=False, + type="str", + choices=["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"]), + ssl_cipher_suites_versions=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + ssl_server_cipher_suites=dict(required=False, type="list"), + ssl_server_cipher_suites_cipher=dict(required=False, + type="str", + choices=["TLS-RSA-WITH-RC4-128-MD5", + "TLS-RSA-WITH-RC4-128-SHA", + "TLS-RSA-WITH-DES-CBC-SHA", + "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA", + "TLS-RSA-WITH-AES-256-CBC-SHA", + "TLS-RSA-WITH-AES-128-CBC-SHA256", + "TLS-RSA-WITH-AES-256-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-RSA-WITH-SEED-CBC-SHA", + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-RSA-WITH-DES-CBC-SHA", + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-RSA-WITH-SEED-CBC-SHA", + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA", + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256", + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + "TLS-RSA-WITH-AES-128-GCM-SHA256", + "TLS-RSA-WITH-AES-256-GCM-SHA384", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA", + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256", + "TLS-DHE-DSS-WITH-SEED-CBC-SHA", + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256", + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA", + "TLS-DHE-DSS-WITH-DES-CBC-SHA"]), + ssl_server_cipher_suites_priority=dict(required=False, type="str"), + ssl_server_cipher_suites_versions=dict(required=False, type="str", + choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "websphere-server": module.params["websphere_server"], + "weblogic-server": module.params["weblogic_server"], + "type": module.params["type"], + "ssl-server-session-state-type": module.params["ssl_server_session_state_type"], + "ssl-server-session-state-timeout": module.params["ssl_server_session_state_timeout"], + "ssl-server-session-state-max": module.params["ssl_server_session_state_max"], + "ssl-server-min-version": module.params["ssl_server_min_version"], + "ssl-server-max-version": module.params["ssl_server_max_version"], + "ssl-server-algorithm": module.params["ssl_server_algorithm"], + "ssl-send-empty-frags": module.params["ssl_send_empty_frags"], + "ssl-pfs": module.params["ssl_pfs"], + "ssl-mode": module.params["ssl_mode"], + "ssl-min-version": module.params["ssl_min_version"], + "ssl-max-version": module.params["ssl_max_version"], + "ssl-http-match-host": module.params["ssl_http_match_host"], + "ssl-http-location-conversion": module.params["ssl_http_location_conversion"], + "ssl-hsts-include-subdomains": module.params["ssl_hsts_include_subdomains"], + "ssl-hsts-age": module.params["ssl_hsts_age"], + "ssl-hsts": module.params["ssl_hsts"], + "ssl-hpkp-report-uri": module.params["ssl_hpkp_report_uri"], + "ssl-hpkp-primary": module.params["ssl_hpkp_primary"], + "ssl-hpkp-include-subdomains": module.params["ssl_hpkp_include_subdomains"], + "ssl-hpkp-backup": module.params["ssl_hpkp_backup"], + "ssl-hpkp-age": module.params["ssl_hpkp_age"], + "ssl-hpkp": module.params["ssl_hpkp"], + "ssl-dh-bits": module.params["ssl_dh_bits"], + "ssl-client-session-state-type": module.params["ssl_client_session_state_type"], + "ssl-client-session-state-timeout": module.params["ssl_client_session_state_timeout"], + "ssl-client-session-state-max": module.params["ssl_client_session_state_max"], + "ssl-client-renegotiation": module.params["ssl_client_renegotiation"], + "ssl-client-fallback": module.params["ssl_client_fallback"], + "ssl-certificate": module.params["ssl_certificate"], + "ssl-algorithm": module.params["ssl_algorithm"], + "srcintf-filter": module.params["srcintf_filter"], + "src-filter": module.params["src_filter"], + "service": module.params["service"], + "server-type": module.params["server_type"], + "protocol": module.params["protocol"], + "portmapping-type": module.params["portmapping_type"], + "portforward": module.params["portforward"], + "persistence": module.params["persistence"], + "outlook-web-access": module.params["outlook_web_access"], + "nat-source-vip": module.params["nat_source_vip"], + "name": module.params["name"], + "monitor": module.params["monitor"], + "max-embryonic-connections": module.params["max_embryonic_connections"], + "mappedport": module.params["mappedport"], + "mappedip": module.params["mappedip"], + "mapped-addr": module.params["mapped_addr"], + "ldb-method": module.params["ldb_method"], + "https-cookie-secure": module.params["https_cookie_secure"], + "http-multiplex": module.params["http_multiplex"], + "http-ip-header-name": module.params["http_ip_header_name"], + "http-ip-header": module.params["http_ip_header"], + "http-cookie-share": module.params["http_cookie_share"], + "http-cookie-path": module.params["http_cookie_path"], + "http-cookie-generation": module.params["http_cookie_generation"], + "http-cookie-domain-from-host": module.params["http_cookie_domain_from_host"], + "http-cookie-domain": module.params["http_cookie_domain"], + "http-cookie-age": module.params["http_cookie_age"], + "gratuitous-arp-interval": module.params["gratuitous_arp_interval"], + "extport": module.params["extport"], + "extip": module.params["extip"], + "extintf": module.params["extintf"], + "extaddr": module.params["extaddr"], + "dns-mapping-ttl": module.params["dns_mapping_ttl"], + "comment": module.params["comment"], + "color": module.params["color"], + "arp-reply": module.params["arp_reply"], + "dynamic_mapping": { + "arp-reply": module.params["dynamic_mapping_arp_reply"], + "color": module.params["dynamic_mapping_color"], + "comment": module.params["dynamic_mapping_comment"], + "dns-mapping-ttl": module.params["dynamic_mapping_dns_mapping_ttl"], + "extaddr": module.params["dynamic_mapping_extaddr"], + "extintf": module.params["dynamic_mapping_extintf"], + "extip": module.params["dynamic_mapping_extip"], + "extport": module.params["dynamic_mapping_extport"], + "gratuitous-arp-interval": module.params["dynamic_mapping_gratuitous_arp_interval"], + "http-cookie-age": module.params["dynamic_mapping_http_cookie_age"], + "http-cookie-domain": module.params["dynamic_mapping_http_cookie_domain"], + "http-cookie-domain-from-host": module.params["dynamic_mapping_http_cookie_domain_from_host"], + "http-cookie-generation": module.params["dynamic_mapping_http_cookie_generation"], + "http-cookie-path": module.params["dynamic_mapping_http_cookie_path"], + "http-cookie-share": module.params["dynamic_mapping_http_cookie_share"], + "http-ip-header": module.params["dynamic_mapping_http_ip_header"], + "http-ip-header-name": module.params["dynamic_mapping_http_ip_header_name"], + "http-multiplex": module.params["dynamic_mapping_http_multiplex"], + "https-cookie-secure": module.params["dynamic_mapping_https_cookie_secure"], + "ldb-method": module.params["dynamic_mapping_ldb_method"], + "mapped-addr": module.params["dynamic_mapping_mapped_addr"], + "mappedip": module.params["dynamic_mapping_mappedip"], + "mappedport": module.params["dynamic_mapping_mappedport"], + "max-embryonic-connections": module.params["dynamic_mapping_max_embryonic_connections"], + "monitor": module.params["dynamic_mapping_monitor"], + "nat-source-vip": module.params["dynamic_mapping_nat_source_vip"], + "outlook-web-access": module.params["dynamic_mapping_outlook_web_access"], + "persistence": module.params["dynamic_mapping_persistence"], + "portforward": module.params["dynamic_mapping_portforward"], + "portmapping-type": module.params["dynamic_mapping_portmapping_type"], + "protocol": module.params["dynamic_mapping_protocol"], + "server-type": module.params["dynamic_mapping_server_type"], + "service": module.params["dynamic_mapping_service"], + "src-filter": module.params["dynamic_mapping_src_filter"], + "srcintf-filter": module.params["dynamic_mapping_srcintf_filter"], + "ssl-algorithm": module.params["dynamic_mapping_ssl_algorithm"], + "ssl-certificate": module.params["dynamic_mapping_ssl_certificate"], + "ssl-client-fallback": module.params["dynamic_mapping_ssl_client_fallback"], + "ssl-client-renegotiation": module.params["dynamic_mapping_ssl_client_renegotiation"], + "ssl-client-session-state-max": module.params["dynamic_mapping_ssl_client_session_state_max"], + "ssl-client-session-state-timeout": module.params["dynamic_mapping_ssl_client_session_state_timeout"], + "ssl-client-session-state-type": module.params["dynamic_mapping_ssl_client_session_state_type"], + "ssl-dh-bits": module.params["dynamic_mapping_ssl_dh_bits"], + "ssl-hpkp": module.params["dynamic_mapping_ssl_hpkp"], + "ssl-hpkp-age": module.params["dynamic_mapping_ssl_hpkp_age"], + "ssl-hpkp-backup": module.params["dynamic_mapping_ssl_hpkp_backup"], + "ssl-hpkp-include-subdomains": module.params["dynamic_mapping_ssl_hpkp_include_subdomains"], + "ssl-hpkp-primary": module.params["dynamic_mapping_ssl_hpkp_primary"], + "ssl-hpkp-report-uri": module.params["dynamic_mapping_ssl_hpkp_report_uri"], + "ssl-hsts": module.params["dynamic_mapping_ssl_hsts"], + "ssl-hsts-age": module.params["dynamic_mapping_ssl_hsts_age"], + "ssl-hsts-include-subdomains": module.params["dynamic_mapping_ssl_hsts_include_subdomains"], + "ssl-http-location-conversion": module.params["dynamic_mapping_ssl_http_location_conversion"], + "ssl-http-match-host": module.params["dynamic_mapping_ssl_http_match_host"], + "ssl-max-version": module.params["dynamic_mapping_ssl_max_version"], + "ssl-min-version": module.params["dynamic_mapping_ssl_min_version"], + "ssl-mode": module.params["dynamic_mapping_ssl_mode"], + "ssl-pfs": module.params["dynamic_mapping_ssl_pfs"], + "ssl-send-empty-frags": module.params["dynamic_mapping_ssl_send_empty_frags"], + "ssl-server-algorithm": module.params["dynamic_mapping_ssl_server_algorithm"], + "ssl-server-max-version": module.params["dynamic_mapping_ssl_server_max_version"], + "ssl-server-min-version": module.params["dynamic_mapping_ssl_server_min_version"], + "ssl-server-session-state-max": module.params["dynamic_mapping_ssl_server_session_state_max"], + "ssl-server-session-state-timeout": module.params["dynamic_mapping_ssl_server_session_state_timeout"], + "ssl-server-session-state-type": module.params["dynamic_mapping_ssl_server_session_state_type"], + "type": module.params["dynamic_mapping_type"], + "weblogic-server": module.params["dynamic_mapping_weblogic_server"], + "websphere-server": module.params["dynamic_mapping_websphere_server"], + "realservers": { + "client-ip": module.params["dynamic_mapping_realservers_client_ip"], + "healthcheck": module.params["dynamic_mapping_realservers_healthcheck"], + "holddown-interval": module.params["dynamic_mapping_realservers_holddown_interval"], + "http-host": module.params["dynamic_mapping_realservers_http_host"], + "ip": module.params["dynamic_mapping_realservers_ip"], + "max-connections": module.params["dynamic_mapping_realservers_max_connections"], + "monitor": module.params["dynamic_mapping_realservers_monitor"], + "port": module.params["dynamic_mapping_realservers_port"], + "seq": module.params["dynamic_mapping_realservers_seq"], + "status": module.params["dynamic_mapping_realservers_status"], + "weight": module.params["dynamic_mapping_realservers_weight"], + }, + "ssl-cipher-suites": { + "cipher": module.params["dynamic_mapping_ssl_cipher_suites_cipher"], + "versions": module.params["dynamic_mapping_ssl_cipher_suites_versions"], + }, + }, + "realservers": { + "client-ip": module.params["realservers_client_ip"], + "healthcheck": module.params["realservers_healthcheck"], + "holddown-interval": module.params["realservers_holddown_interval"], + "http-host": module.params["realservers_http_host"], + "ip": module.params["realservers_ip"], + "max-connections": module.params["realservers_max_connections"], + "monitor": module.params["realservers_monitor"], + "port": module.params["realservers_port"], + "seq": module.params["realservers_seq"], + "status": module.params["realservers_status"], + "weight": module.params["realservers_weight"], + }, + "ssl-cipher-suites": { + "cipher": module.params["ssl_cipher_suites_cipher"], + "versions": module.params["ssl_cipher_suites_versions"], + }, + "ssl-server-cipher-suites": { + "cipher": module.params["ssl_server_cipher_suites_cipher"], + "priority": module.params["ssl_server_cipher_suites_priority"], + "versions": module.params["ssl_server_cipher_suites_versions"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['dynamic_mapping', 'realservers', 'ssl-cipher-suites', 'ssl-server-cipher-suites'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + try: + results = fmgr_firewall_vip_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py new file mode 100644 index 000000000..f0b0fd9c8 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py @@ -0,0 +1,1355 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwpol_ipv4 +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Allows the add/delete of Firewall Policies on Packages in FortiManager. +description: + - Allows the add/delete of Firewall Policies on Packages in FortiManager. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + package_name: + description: + - The policy package you want to modify + required: false + default: "default" + + fail_on_missing_dependency: + description: + - Normal behavior is to "skip" tasks that fail dependency checks, so other tasks can run. + - If set to "enabled" if a failed dependency check happeens, Ansible will exit as with failure instead of skip. + required: false + default: "disable" + choices: ["enable", "disable"] + + wsso: + description: + - Enable/disable WiFi Single Sign On (WSSO). + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + webfilter_profile: + description: + - Name of an existing Web filter profile. + required: false + + webcache_https: + description: + - Enable/disable web cache for HTTPS. + - choice | disable | Disable web cache for HTTPS. + - choice | enable | Enable web cache for HTTPS. + required: false + choices: ["disable", "enable"] + + webcache: + description: + - Enable/disable web cache. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + wccp: + description: + - Enable/disable forwarding traffic matching this policy to a configured WCCP server. + - choice | disable | Disable WCCP setting. + - choice | enable | Enable WCCP setting. + required: false + choices: ["disable", "enable"] + + wanopt_profile: + description: + - WAN optimization profile. + required: false + + wanopt_peer: + description: + - WAN optimization peer. + required: false + + wanopt_passive_opt: + description: + - WAN optimization passive mode options. This option decides what IP address will be used to connect server. + - choice | default | Allow client side WAN opt peer to decide. + - choice | transparent | Use address of client to connect to server. + - choice | non-transparent | Use local FortiGate address to connect to server. + required: false + choices: ["default", "transparent", "non-transparent"] + + wanopt_detection: + description: + - WAN optimization auto-detection mode. + - choice | active | Active WAN optimization peer auto-detection. + - choice | passive | Passive WAN optimization peer auto-detection. + - choice | off | Turn off WAN optimization peer auto-detection. + required: false + choices: ["active", "passive", "off"] + + wanopt: + description: + - Enable/disable WAN optimization. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + waf_profile: + description: + - Name of an existing Web application firewall profile. + required: false + + vpntunnel: + description: + - Policy-based IPsec VPN | name of the IPsec VPN Phase 1. + required: false + + voip_profile: + description: + - Name of an existing VoIP profile. + required: false + + vlan_filter: + description: + - Set VLAN filters. + required: false + + vlan_cos_rev: + description: + - VLAN reverse direction user priority | 255 passthrough, 0 lowest, 7 highest.. + required: false + + vlan_cos_fwd: + description: + - VLAN forward direction user priority | 255 passthrough, 0 lowest, 7 highest. + required: false + + utm_status: + description: + - Enable to add one or more security profiles (AV, IPS, etc.) to the firewall policy. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + users: + description: + - Names of individual users that can authenticate with this policy. + required: false + + url_category: + description: + - URL category ID list. + required: false + + traffic_shaper_reverse: + description: + - Reverse traffic shaper. + required: false + + traffic_shaper: + description: + - Traffic shaper. + required: false + + timeout_send_rst: + description: + - Enable/disable sending RST packets when TCP sessions expire. + - choice | disable | Disable sending of RST packet upon TCP session expiration. + - choice | enable | Enable sending of RST packet upon TCP session expiration. + required: false + choices: ["disable", "enable"] + + tcp_session_without_syn: + description: + - Enable/disable creation of TCP session without SYN flag. + - choice | all | Enable TCP session without SYN. + - choice | data-only | Enable TCP session data only. + - choice | disable | Disable TCP session without SYN. + required: false + choices: ["all", "data-only", "disable"] + + tcp_mss_sender: + description: + - Sender TCP maximum segment size (MSS). + required: false + + tcp_mss_receiver: + description: + - Receiver TCP maximum segment size (MSS). + required: false + + status: + description: + - Enable or disable this policy. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ssl_ssh_profile: + description: + - Name of an existing SSL SSH profile. + required: false + + ssl_mirror_intf: + description: + - SSL mirror interface name. + required: false + + ssl_mirror: + description: + - Enable to copy decrypted SSL traffic to a FortiGate interface (called SSL mirroring). + - choice | disable | Disable SSL mirror. + - choice | enable | Enable SSL mirror. + required: false + choices: ["disable", "enable"] + + ssh_filter_profile: + description: + - Name of an existing SSH filter profile. + required: false + + srcintf: + description: + - Incoming (ingress) interface. + required: false + + srcaddr_negate: + description: + - When enabled srcaddr specifies what the source address must NOT be. + - choice | disable | Disable source address negate. + - choice | enable | Enable source address negate. + required: false + choices: ["disable", "enable"] + + srcaddr: + description: + - Source address and address group names. + required: false + + spamfilter_profile: + description: + - Name of an existing Spam filter profile. + required: false + + session_ttl: + description: + - TTL in seconds for sessions accepted by this policy (0 means use the system default session TTL). + required: false + + service_negate: + description: + - When enabled service specifies what the service must NOT be. + - choice | disable | Disable negated service match. + - choice | enable | Enable negated service match. + required: false + choices: ["disable", "enable"] + + service: + description: + - Service and service group names. + required: false + + send_deny_packet: + description: + - Enable to send a reply when a session is denied or blocked by a firewall policy. + - choice | disable | Disable deny-packet sending. + - choice | enable | Enable deny-packet sending. + required: false + choices: ["disable", "enable"] + + schedule_timeout: + description: + - Enable to force current sessions to end when the schedule object times out. + - choice | disable | Disable schedule timeout. + - choice | enable | Enable schedule timeout. + required: false + choices: ["disable", "enable"] + + schedule: + description: + - Schedule name. + required: false + + scan_botnet_connections: + description: + - Block or monitor connections to Botnet servers or disable Botnet scanning. + - choice | disable | Do not scan connections to botnet servers. + - choice | block | Block connections to botnet servers. + - choice | monitor | Log connections to botnet servers. + required: false + choices: ["disable", "block", "monitor"] + + rtp_nat: + description: + - Enable Real Time Protocol (RTP) NAT. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + rtp_addr: + description: + - Address names if this is an RTP NAT policy. + required: false + + rsso: + description: + - Enable/disable RADIUS single sign-on (RSSO). + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + replacemsg_override_group: + description: + - Override the default replacement message group for this policy. + required: false + + redirect_url: + description: + - URL users are directed to after seeing and accepting the disclaimer or authenticating. + required: false + + radius_mac_auth_bypass: + description: + - Enable MAC authentication bypass. The bypassed MAC address must be received from RADIUS server. + - choice | disable | Disable MAC authentication bypass. + - choice | enable | Enable MAC authentication bypass. + required: false + choices: ["disable", "enable"] + + profile_type: + description: + - Determine whether the firewall policy allows security profile groups or single profiles only. + - choice | single | Do not allow security profile groups. + - choice | group | Allow security profile groups. + required: false + choices: ["single", "group"] + + profile_protocol_options: + description: + - Name of an existing Protocol options profile. + required: false + + profile_group: + description: + - Name of profile group. + required: false + + poolname: + description: + - IP Pool names. + required: false + + policyid: + description: + - Policy ID. + required: false + + permit_stun_host: + description: + - Accept UDP packets from any Session Traversal Utilities for NAT (STUN) host. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + permit_any_host: + description: + - Accept UDP packets from any host. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + per_ip_shaper: + description: + - Per-IP traffic shaper. + required: false + + outbound: + description: + - Policy-based IPsec VPN | only traffic from the internal network can initiate a VPN. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ntlm_guest: + description: + - Enable/disable NTLM guest user access. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ntlm_enabled_browsers: + description: + - HTTP-User-Agent value of supported browsers. + required: false + + ntlm: + description: + - Enable/disable NTLM authentication. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + np_acceleration: + description: + - Enable/disable UTM Network Processor acceleration. + - choice | disable | Disable UTM Network Processor acceleration. + - choice | enable | Enable UTM Network Processor acceleration. + required: false + choices: ["disable", "enable"] + + natoutbound: + description: + - Policy-based IPsec VPN | apply source NAT to outbound traffic. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + natip: + description: + - Policy-based IPsec VPN | source NAT IP address for outgoing traffic. + required: false + + natinbound: + description: + - Policy-based IPsec VPN | apply destination NAT to inbound traffic. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + nat: + description: + - Enable/disable source NAT. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + name: + description: + - Policy name. + required: false + + mms_profile: + description: + - Name of an existing MMS profile. + required: false + + match_vip: + description: + - Enable to match packets that have had their destination addresses changed by a VIP. + - choice | disable | Do not match DNATed packet. + - choice | enable | Match DNATed packet. + required: false + choices: ["disable", "enable"] + + logtraffic_start: + description: + - Record logs when a session starts and ends. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + logtraffic: + description: + - Enable or disable logging. Log all sessions or security profile sessions. + - choice | disable | Disable all logging for this policy. + - choice | all | Log all sessions accepted or denied by this policy. + - choice | utm | Log traffic that has a security profile applied to it. + required: false + choices: ["disable", "all", "utm"] + + learning_mode: + description: + - Enable to allow everything, but log all of the meaningful data for security information gathering. + - choice | disable | Disable learning mode in firewall policy. + - choice | enable | Enable learning mode in firewall policy. + required: false + choices: ["disable", "enable"] + + label: + description: + - Label for the policy that appears when the GUI is in Section View mode. + required: false + + ips_sensor: + description: + - Name of an existing IPS sensor. + required: false + + ippool: + description: + - Enable to use IP Pools for source NAT. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + internet_service_src_negate: + description: + - When enabled internet-service-src specifies what the service must NOT be. + - choice | disable | Disable negated Internet Service source match. + - choice | enable | Enable negated Internet Service source match. + required: false + choices: ["disable", "enable"] + + internet_service_src_id: + description: + - Internet Service source ID. + required: false + + internet_service_src_custom: + description: + - Custom Internet Service source name. + required: false + + internet_service_src: + description: + - Enable/disable use of Internet Services in source for this policy. If enabled, source address is not used. + - choice | disable | Disable use of Internet Services source in policy. + - choice | enable | Enable use of Internet Services source in policy. + required: false + choices: ["disable", "enable"] + + internet_service_negate: + description: + - When enabled internet-service specifies what the service must NOT be. + - choice | disable | Disable negated Internet Service match. + - choice | enable | Enable negated Internet Service match. + required: false + choices: ["disable", "enable"] + + internet_service_id: + description: + - Internet Service ID. + required: false + + internet_service_custom: + description: + - Custom Internet Service name. + required: false + + internet_service: + description: + - Enable/disable use of Internet Services for this policy. If enabled, dstaddr and service are not used. + - choice | disable | Disable use of Internet Services in policy. + - choice | enable | Enable use of Internet Services in policy. + required: false + choices: ["disable", "enable"] + + inbound: + description: + - Policy-based IPsec VPN | only traffic from the remote network can initiate a VPN. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + identity_based_route: + description: + - Name of identity-based routing rule. + required: false + + icap_profile: + description: + - Name of an existing ICAP profile. + required: false + + gtp_profile: + description: + - GTP profile. + required: false + + groups: + description: + - Names of user groups that can authenticate with this policy. + required: false + + global_label: + description: + - Label for the policy that appears when the GUI is in Global View mode. + required: false + + fsso_agent_for_ntlm: + description: + - FSSO agent to use for NTLM authentication. + required: false + + fsso: + description: + - Enable/disable Fortinet Single Sign-On. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + fixedport: + description: + - Enable to prevent source NAT from changing a session's source port. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + firewall_session_dirty: + description: + - How to handle sessions if the configuration of this firewall policy changes. + - choice | check-all | Flush all current sessions accepted by this policy. + - choice | check-new | Continue to allow sessions already accepted by this policy. + required: false + choices: ["check-all", "check-new"] + + dstintf: + description: + - Outgoing (egress) interface. + required: false + + dstaddr_negate: + description: + - When enabled dstaddr specifies what the destination address must NOT be. + - choice | disable | Disable destination address negate. + - choice | enable | Enable destination address negate. + required: false + choices: ["disable", "enable"] + + dstaddr: + description: + - Destination address and address group names. + required: false + + dsri: + description: + - Enable DSRI to ignore HTTP server responses. + - choice | disable | Disable DSRI. + - choice | enable | Enable DSRI. + required: false + choices: ["disable", "enable"] + + dscp_value: + description: + - DSCP value. + required: false + + dscp_negate: + description: + - Enable negated DSCP match. + - choice | disable | Disable DSCP negate. + - choice | enable | Enable DSCP negate. + required: false + choices: ["disable", "enable"] + + dscp_match: + description: + - Enable DSCP check. + - choice | disable | Disable DSCP check. + - choice | enable | Enable DSCP check. + required: false + choices: ["disable", "enable"] + + dnsfilter_profile: + description: + - Name of an existing DNS filter profile. + required: false + + dlp_sensor: + description: + - Name of an existing DLP sensor. + required: false + + disclaimer: + description: + - Enable/disable user authentication disclaimer. + - choice | disable | Disable user authentication disclaimer. + - choice | enable | Enable user authentication disclaimer. + required: false + choices: ["disable", "enable"] + + diffservcode_rev: + description: + - Change packet's reverse (reply) DiffServ to this value. + required: false + + diffservcode_forward: + description: + - Change packet's DiffServ to this value. + required: false + + diffserv_reverse: + description: + - Enable to change packet's reverse (reply) DiffServ values to the specified diffservcode-rev value. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + diffserv_forward: + description: + - Enable to change packet's DiffServ values to the specified diffservcode-forward value. + - choice | disable | Disable WAN optimization. + - choice | enable | Enable WAN optimization. + required: false + choices: ["disable", "enable"] + + devices: + description: + - Names of devices or device groups that can be matched by the policy. + required: false + + delay_tcp_npu_session: + description: + - Enable TCP NPU session delay to guarantee packet order of 3-way handshake. + - choice | disable | Disable TCP NPU session delay in order to guarantee packet order of 3-way handshake. + - choice | enable | Enable TCP NPU session delay in order to guarantee packet order of 3-way handshake. + required: false + choices: ["disable", "enable"] + + custom_log_fields: + description: + - Custom fields to append to log messages for this policy. + required: false + + comments: + description: + - Comment. + required: false + + capture_packet: + description: + - Enable/disable capture packets. + - choice | disable | Disable capture packets. + - choice | enable | Enable capture packets. + required: false + choices: ["disable", "enable"] + + captive_portal_exempt: + description: + - Enable to exempt some users from the captive portal. + - choice | disable | Disable exemption of captive portal. + - choice | enable | Enable exemption of captive portal. + required: false + choices: ["disable", "enable"] + + block_notification: + description: + - Enable/disable block notification. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + av_profile: + description: + - Name of an existing Antivirus profile. + required: false + + auto_asic_offload: + description: + - Enable/disable offloading security profile processing to CP processors. + - choice | disable | Disable ASIC offloading. + - choice | enable | Enable auto ASIC offloading. + required: false + choices: ["disable", "enable"] + + auth_redirect_addr: + description: + - HTTP-to-HTTPS redirect address for firewall authentication. + required: false + + auth_path: + description: + - Enable/disable authentication-based routing. + - choice | disable | Disable authentication-based routing. + - choice | enable | Enable authentication-based routing. + required: false + choices: ["disable", "enable"] + + auth_cert: + description: + - HTTPS server certificate for policy authentication. + required: false + + application_list: + description: + - Name of an existing Application list. + required: false + + application: + description: + - Application ID list. + required: false + + app_group: + description: + - Application group names. + required: false + + app_category: + description: + - Application category ID list. + required: false + + action: + description: + - Policy action (allow/deny/ipsec). + - choice | deny | Blocks sessions that match the firewall policy. + - choice | accept | Allows session that match the firewall policy. + - choice | ipsec | Firewall policy becomes a policy-based IPsec VPN policy. + required: false + choices: ["deny", "accept", "ipsec"] + + vpn_dst_node: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + required: false + + vpn_dst_node_host: + description: + - VPN Destination Node Host. + required: false + + vpn_dst_node_seq: + description: + - VPN Destination Node Seq. + required: false + + vpn_dst_node_subnet: + description: + - VPN Destination Node Seq. + required: false + + vpn_src_node: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + required: false + + vpn_src_node_host: + description: + - VPN Source Node Host. + required: false + + vpn_src_node_seq: + description: + - VPN Source Node Seq. + required: false + + vpn_src_node_subnet: + description: + - VPN Source Node. + required: false + + +''' + +EXAMPLES = ''' +- name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN) + community.fortios.fmgr_fwpol_ipv4: + mode: "set" + adom: "ansible" + package_name: "default" + name: "Basic_IPv4_Policy" + comments: "Created by Ansible" + action: "accept" + dstaddr: "all" + srcaddr: "all" + dstintf: "any" + srcintf: "any" + logtraffic: "utm" + service: "ALL" + schedule: "always" + +- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES + community.fortios.fmgr_fwpol_ipv4: + mode: "set" + adom: "ansible" + package_name: "default" + name: "Basic_IPv4_Policy_2" + comments: "Created by Ansible" + action: "accept" + dstaddr: "google-play" + srcaddr: "all" + dstintf: "any" + srcintf: "any" + logtraffic: "utm" + service: "HTTP, HTTPS" + schedule: "always" + nat: "enable" + users: "karen, kevin" + +- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES AND SEC PROFILES + community.fortios.fmgr_fwpol_ipv4: + mode: "set" + adom: "ansible" + package_name: "default" + name: "Basic_IPv4_Policy_3" + comments: "Created by Ansible" + action: "accept" + dstaddr: "google-play, autoupdate.opera.com" + srcaddr: "corp_internal" + dstintf: "zone_wan1, zone_wan2" + srcintf: "zone_int1" + logtraffic: "utm" + service: "HTTP, HTTPS" + schedule: "always" + nat: "enable" + users: "karen, kevin" + av_profile: "sniffer-profile" + ips_sensor: "default" + +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +def fmgr_firewall_policy_modify(fmgr, paramgram): + """ + fmgr_firewall_policy -- Add/Set/Deletes Firewall Policy Objects defined in the "paramgram" + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall/policy'.format(adom=adom, pkg=paramgram["package_name"]) + datagram = scrub_dict((prepare_dict(paramgram))) + del datagram["package_name"] + datagram = fmgr._tools.split_comma_strings_into_lists(datagram) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \ + '/policy/{policyid}'.format(adom=paramgram["adom"], + pkg=paramgram["package_name"], + policyid=paramgram["policyid"]) + datagram = { + "policyid": paramgram["policyid"] + } + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + package_name=dict(type="str", required=False, default="default"), + fail_on_missing_dependency=dict(type="str", required=False, default="disable", choices=["enable", + "disable"]), + wsso=dict(required=False, type="str", choices=["disable", "enable"]), + webfilter_profile=dict(required=False, type="str"), + webcache_https=dict(required=False, type="str", choices=["disable", "enable"]), + webcache=dict(required=False, type="str", choices=["disable", "enable"]), + wccp=dict(required=False, type="str", choices=["disable", "enable"]), + wanopt_profile=dict(required=False, type="str"), + wanopt_peer=dict(required=False, type="str"), + wanopt_passive_opt=dict(required=False, type="str", choices=["default", "transparent", "non-transparent"]), + wanopt_detection=dict(required=False, type="str", choices=["active", "passive", "off"]), + wanopt=dict(required=False, type="str", choices=["disable", "enable"]), + waf_profile=dict(required=False, type="str"), + vpntunnel=dict(required=False, type="str"), + voip_profile=dict(required=False, type="str"), + vlan_filter=dict(required=False, type="str"), + vlan_cos_rev=dict(required=False, type="int"), + vlan_cos_fwd=dict(required=False, type="int"), + utm_status=dict(required=False, type="str", choices=["disable", "enable"]), + users=dict(required=False, type="str"), + url_category=dict(required=False, type="str"), + traffic_shaper_reverse=dict(required=False, type="str"), + traffic_shaper=dict(required=False, type="str"), + timeout_send_rst=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_session_without_syn=dict(required=False, type="str", choices=["all", "data-only", "disable"]), + tcp_mss_sender=dict(required=False, type="int"), + tcp_mss_receiver=dict(required=False, type="int"), + status=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_ssh_profile=dict(required=False, type="str"), + ssl_mirror_intf=dict(required=False, type="str"), + ssl_mirror=dict(required=False, type="str", choices=["disable", "enable"]), + ssh_filter_profile=dict(required=False, type="str"), + srcintf=dict(required=False, type="str"), + srcaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]), + srcaddr=dict(required=False, type="str"), + spamfilter_profile=dict(required=False, type="str"), + session_ttl=dict(required=False, type="int"), + service_negate=dict(required=False, type="str", choices=["disable", "enable"]), + service=dict(required=False, type="str"), + send_deny_packet=dict(required=False, type="str", choices=["disable", "enable"]), + schedule_timeout=dict(required=False, type="str", choices=["disable", "enable"]), + schedule=dict(required=False, type="str"), + scan_botnet_connections=dict(required=False, type="str", choices=["disable", "block", "monitor"]), + rtp_nat=dict(required=False, type="str", choices=["disable", "enable"]), + rtp_addr=dict(required=False, type="str"), + rsso=dict(required=False, type="str", choices=["disable", "enable"]), + replacemsg_override_group=dict(required=False, type="str"), + redirect_url=dict(required=False, type="str"), + radius_mac_auth_bypass=dict(required=False, type="str", choices=["disable", "enable"]), + profile_type=dict(required=False, type="str", choices=["single", "group"]), + profile_protocol_options=dict(required=False, type="str"), + profile_group=dict(required=False, type="str"), + poolname=dict(required=False, type="str"), + policyid=dict(required=False, type="str"), + permit_stun_host=dict(required=False, type="str", choices=["disable", "enable"]), + permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]), + per_ip_shaper=dict(required=False, type="str"), + outbound=dict(required=False, type="str", choices=["disable", "enable"]), + ntlm_guest=dict(required=False, type="str", choices=["disable", "enable"]), + ntlm_enabled_browsers=dict(required=False, type="str"), + ntlm=dict(required=False, type="str", choices=["disable", "enable"]), + np_acceleration=dict(required=False, type="str", choices=["disable", "enable"]), + natoutbound=dict(required=False, type="str", choices=["disable", "enable"]), + natip=dict(required=False, type="str"), + natinbound=dict(required=False, type="str", choices=["disable", "enable"]), + nat=dict(required=False, type="str", choices=["disable", "enable"]), + name=dict(required=False, type="str"), + mms_profile=dict(required=False, type="str"), + match_vip=dict(required=False, type="str", choices=["disable", "enable"]), + logtraffic_start=dict(required=False, type="str", choices=["disable", "enable"]), + logtraffic=dict(required=False, type="str", choices=["disable", "all", "utm"]), + learning_mode=dict(required=False, type="str", choices=["disable", "enable"]), + label=dict(required=False, type="str"), + ips_sensor=dict(required=False, type="str"), + ippool=dict(required=False, type="str", choices=["disable", "enable"]), + internet_service_src_negate=dict(required=False, type="str", choices=["disable", "enable"]), + internet_service_src_id=dict(required=False, type="str"), + internet_service_src_custom=dict(required=False, type="str"), + internet_service_src=dict(required=False, type="str", choices=["disable", "enable"]), + internet_service_negate=dict(required=False, type="str", choices=["disable", "enable"]), + internet_service_id=dict(required=False, type="str"), + internet_service_custom=dict(required=False, type="str"), + internet_service=dict(required=False, type="str", choices=["disable", "enable"]), + inbound=dict(required=False, type="str", choices=["disable", "enable"]), + identity_based_route=dict(required=False, type="str"), + icap_profile=dict(required=False, type="str"), + gtp_profile=dict(required=False, type="str"), + groups=dict(required=False, type="str"), + global_label=dict(required=False, type="str"), + fsso_agent_for_ntlm=dict(required=False, type="str"), + fsso=dict(required=False, type="str", choices=["disable", "enable"]), + fixedport=dict(required=False, type="str", choices=["disable", "enable"]), + firewall_session_dirty=dict(required=False, type="str", choices=["check-all", "check-new"]), + dstintf=dict(required=False, type="str"), + dstaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]), + dstaddr=dict(required=False, type="str"), + dsri=dict(required=False, type="str", choices=["disable", "enable"]), + dscp_value=dict(required=False, type="str"), + dscp_negate=dict(required=False, type="str", choices=["disable", "enable"]), + dscp_match=dict(required=False, type="str", choices=["disable", "enable"]), + dnsfilter_profile=dict(required=False, type="str"), + dlp_sensor=dict(required=False, type="str"), + disclaimer=dict(required=False, type="str", choices=["disable", "enable"]), + diffservcode_rev=dict(required=False, type="str"), + diffservcode_forward=dict(required=False, type="str"), + diffserv_reverse=dict(required=False, type="str", choices=["disable", "enable"]), + diffserv_forward=dict(required=False, type="str", choices=["disable", "enable"]), + devices=dict(required=False, type="str"), + delay_tcp_npu_session=dict(required=False, type="str", choices=["disable", "enable"]), + custom_log_fields=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + capture_packet=dict(required=False, type="str", choices=["disable", "enable"]), + captive_portal_exempt=dict(required=False, type="str", choices=["disable", "enable"]), + block_notification=dict(required=False, type="str", choices=["disable", "enable"]), + av_profile=dict(required=False, type="str"), + auto_asic_offload=dict(required=False, type="str", choices=["disable", "enable"]), + auth_redirect_addr=dict(required=False, type="str"), + auth_path=dict(required=False, type="str", choices=["disable", "enable"]), + auth_cert=dict(required=False, type="str"), + application_list=dict(required=False, type="str"), + application=dict(required=False, type="str"), + app_group=dict(required=False, type="str"), + app_category=dict(required=False, type="str"), + action=dict(required=False, type="str", choices=["deny", "accept", "ipsec"]), + vpn_dst_node=dict(required=False, type="list"), + vpn_dst_node_host=dict(required=False, type="str"), + vpn_dst_node_seq=dict(required=False, type="str"), + vpn_dst_node_subnet=dict(required=False, type="str"), + vpn_src_node=dict(required=False, type="list"), + vpn_src_node_host=dict(required=False, type="str"), + vpn_src_node_seq=dict(required=False, type="str"), + vpn_src_node_subnet=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "package_name": module.params["package_name"], + "wsso": module.params["wsso"], + "webfilter-profile": module.params["webfilter_profile"], + "webcache-https": module.params["webcache_https"], + "webcache": module.params["webcache"], + "wccp": module.params["wccp"], + "wanopt-profile": module.params["wanopt_profile"], + "wanopt-peer": module.params["wanopt_peer"], + "wanopt-passive-opt": module.params["wanopt_passive_opt"], + "wanopt-detection": module.params["wanopt_detection"], + "wanopt": module.params["wanopt"], + "waf-profile": module.params["waf_profile"], + "vpntunnel": module.params["vpntunnel"], + "voip-profile": module.params["voip_profile"], + "vlan-filter": module.params["vlan_filter"], + "vlan-cos-rev": module.params["vlan_cos_rev"], + "vlan-cos-fwd": module.params["vlan_cos_fwd"], + "utm-status": module.params["utm_status"], + "users": module.params["users"], + "url-category": module.params["url_category"], + "traffic-shaper-reverse": module.params["traffic_shaper_reverse"], + "traffic-shaper": module.params["traffic_shaper"], + "timeout-send-rst": module.params["timeout_send_rst"], + "tcp-session-without-syn": module.params["tcp_session_without_syn"], + "tcp-mss-sender": module.params["tcp_mss_sender"], + "tcp-mss-receiver": module.params["tcp_mss_receiver"], + "status": module.params["status"], + "ssl-ssh-profile": module.params["ssl_ssh_profile"], + "ssl-mirror-intf": module.params["ssl_mirror_intf"], + "ssl-mirror": module.params["ssl_mirror"], + "ssh-filter-profile": module.params["ssh_filter_profile"], + "srcintf": module.params["srcintf"], + "srcaddr-negate": module.params["srcaddr_negate"], + "srcaddr": module.params["srcaddr"], + "spamfilter-profile": module.params["spamfilter_profile"], + "session-ttl": module.params["session_ttl"], + "service-negate": module.params["service_negate"], + "service": module.params["service"], + "send-deny-packet": module.params["send_deny_packet"], + "schedule-timeout": module.params["schedule_timeout"], + "schedule": module.params["schedule"], + "scan-botnet-connections": module.params["scan_botnet_connections"], + "rtp-nat": module.params["rtp_nat"], + "rtp-addr": module.params["rtp_addr"], + "rsso": module.params["rsso"], + "replacemsg-override-group": module.params["replacemsg_override_group"], + "redirect-url": module.params["redirect_url"], + "radius-mac-auth-bypass": module.params["radius_mac_auth_bypass"], + "profile-type": module.params["profile_type"], + "profile-protocol-options": module.params["profile_protocol_options"], + "profile-group": module.params["profile_group"], + "poolname": module.params["poolname"], + "policyid": module.params["policyid"], + "permit-stun-host": module.params["permit_stun_host"], + "permit-any-host": module.params["permit_any_host"], + "per-ip-shaper": module.params["per_ip_shaper"], + "outbound": module.params["outbound"], + "ntlm-guest": module.params["ntlm_guest"], + "ntlm-enabled-browsers": module.params["ntlm_enabled_browsers"], + "ntlm": module.params["ntlm"], + "np-acceleration": module.params["np_acceleration"], + "natoutbound": module.params["natoutbound"], + "natip": module.params["natip"], + "natinbound": module.params["natinbound"], + "nat": module.params["nat"], + "name": module.params["name"], + "mms-profile": module.params["mms_profile"], + "match-vip": module.params["match_vip"], + "logtraffic-start": module.params["logtraffic_start"], + "logtraffic": module.params["logtraffic"], + "learning-mode": module.params["learning_mode"], + "label": module.params["label"], + "ips-sensor": module.params["ips_sensor"], + "ippool": module.params["ippool"], + "internet-service-src-negate": module.params["internet_service_src_negate"], + "internet-service-src-id": module.params["internet_service_src_id"], + "internet-service-src-custom": module.params["internet_service_src_custom"], + "internet-service-src": module.params["internet_service_src"], + "internet-service-negate": module.params["internet_service_negate"], + "internet-service-id": module.params["internet_service_id"], + "internet-service-custom": module.params["internet_service_custom"], + "internet-service": module.params["internet_service"], + "inbound": module.params["inbound"], + "identity-based-route": module.params["identity_based_route"], + "icap-profile": module.params["icap_profile"], + "gtp-profile": module.params["gtp_profile"], + "groups": module.params["groups"], + "global-label": module.params["global_label"], + "fsso-agent-for-ntlm": module.params["fsso_agent_for_ntlm"], + "fsso": module.params["fsso"], + "fixedport": module.params["fixedport"], + "firewall-session-dirty": module.params["firewall_session_dirty"], + "dstintf": module.params["dstintf"], + "dstaddr-negate": module.params["dstaddr_negate"], + "dstaddr": module.params["dstaddr"], + "dsri": module.params["dsri"], + "dscp-value": module.params["dscp_value"], + "dscp-negate": module.params["dscp_negate"], + "dscp-match": module.params["dscp_match"], + "dnsfilter-profile": module.params["dnsfilter_profile"], + "dlp-sensor": module.params["dlp_sensor"], + "disclaimer": module.params["disclaimer"], + "diffservcode-rev": module.params["diffservcode_rev"], + "diffservcode-forward": module.params["diffservcode_forward"], + "diffserv-reverse": module.params["diffserv_reverse"], + "diffserv-forward": module.params["diffserv_forward"], + "devices": module.params["devices"], + "delay-tcp-npu-session": module.params["delay_tcp_npu_session"], + "custom-log-fields": module.params["custom_log_fields"], + "comments": module.params["comments"], + "capture-packet": module.params["capture_packet"], + "captive-portal-exempt": module.params["captive_portal_exempt"], + "block-notification": module.params["block_notification"], + "av-profile": module.params["av_profile"], + "auto-asic-offload": module.params["auto_asic_offload"], + "auth-redirect-addr": module.params["auth_redirect_addr"], + "auth-path": module.params["auth_path"], + "auth-cert": module.params["auth_cert"], + "application-list": module.params["application_list"], + "application": module.params["application"], + "app-group": module.params["app_group"], + "app-category": module.params["app_category"], + "action": module.params["action"], + "vpn_dst_node": { + "host": module.params["vpn_dst_node_host"], + "seq": module.params["vpn_dst_node_seq"], + "subnet": module.params["vpn_dst_node_subnet"], + }, + "vpn_src_node": { + "host": module.params["vpn_src_node_host"], + "seq": module.params["vpn_src_node_seq"], + "subnet": module.params["vpn_src_node_subnet"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['vpn_dst_node', 'vpn_src_node'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + try: + if paramgram["mode"] == "delete": + # WE NEED TO GET THE POLICY ID FROM THE NAME OF THE POLICY TO DELETE IT + url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \ + '/policy/'.format(adom=paramgram["adom"], + pkg=paramgram["package_name"]) + datagram = { + "filter": ["name", "==", paramgram["name"]] + } + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + try: + if response[1][0]["policyid"]: + policy_id = response[1][0]["policyid"] + paramgram["policyid"] = policy_id + except BaseException: + fmgr.return_response(module=module, results=response, good_codes=[0, ], stop_on_success=True, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram), + msg="Couldn't find policy ID number for policy name specified.") + except Exception as err: + raise FMGBaseException(err) + + try: + results = fmgr_firewall_policy_modify(fmgr, paramgram) + if module.params["fail_on_missing_dependency"] == "disable": + fmgr.govern_response(module=module, results=results, good_codes=[0, -9998], + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + if module.params["fail_on_missing_dependency"] == "enable" and results[0] == -10131: + fmgr.govern_response(module=module, results=results, good_codes=[0, ], failed=True, skipped=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py new file mode 100644 index 000000000..7b65393fd --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py @@ -0,0 +1,479 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_fwpol_package +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manages FortiManager Firewall Policies Packages. +description: + - Manages FortiManager Firewall Policies Packages. Policy Packages contain one or more Firewall Policies/Rules and + are distritbuted via FortiManager to Fortigates. + - This module controls the creation/edit/delete/assign of these packages. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + choices: ['add', 'set', 'delete'] + default: add + + name: + description: + - Name of the FortiManager package or folder. + required: True + + object_type: + description: + - Are we managing packages or folders, or installing packages? + required: True + choices: ['pkg','folder','install'] + + package_folder: + description: + - Name of the folder you want to put the package into. + required: false + + central_nat: + description: + - Central NAT setting. + required: false + choices: ['enable', 'disable'] + default: disable + + fwpolicy_implicit_log: + description: + - Implicit Log setting for all IPv4 policies in package. + required: false + choices: ['enable', 'disable'] + default: disable + + fwpolicy6_implicit_log: + description: + - Implicit Log setting for all IPv6 policies in package. + required: false + choices: ['enable', 'disable'] + default: disable + + inspection_mode: + description: + - Inspection mode setting for the policies flow or proxy. + required: false + choices: ['flow', 'proxy'] + default: flow + + ngfw_mode: + description: + - NGFW mode setting for the policies flow or proxy. + required: false + choices: ['profile-based', 'policy-based'] + default: profile-based + + ssl_ssh_profile: + description: + - if policy-based ngfw-mode, refer to firewall ssl-ssh-profile. + required: false + + scope_members: + description: + - The devices or scope that you want to assign this policy package to. + required: false + + scope_members_vdom: + description: + - The members VDOM you want to assign the package to. + required: false + default: root + + parent_folder: + description: + - The parent folder name you want to add this object under. + required: false + +''' + + +EXAMPLES = ''' +- name: CREATE BASIC POLICY PACKAGE + community.fortios.fmgr_fwpol_package: + adom: "ansible" + mode: "add" + name: "testPackage" + object_type: "pkg" + +- name: ADD PACKAGE WITH TARGETS + community.fortios.fmgr_fwpol_package: + mode: "add" + adom: "ansible" + name: "ansibleTestPackage1" + object_type: "pkg" + inspection_mode: "flow" + ngfw_mode: "profile-based" + scope_members: "seattle-fgt02, seattle-fgt03" + +- name: ADD FOLDER + community.fortios.fmgr_fwpol_package: + mode: "add" + adom: "ansible" + name: "ansibleTestFolder1" + object_type: "folder" + +- name: ADD PACKAGE INTO PARENT FOLDER + community.fortios.fmgr_fwpol_package: + mode: "set" + adom: "ansible" + name: "ansibleTestPackage2" + object_type: "pkg" + parent_folder: "ansibleTestFolder1" + +- name: ADD FOLDER INTO PARENT FOLDER + community.fortios.fmgr_fwpol_package: + mode: "set" + adom: "ansible" + name: "ansibleTestFolder2" + object_type: "folder" + parent_folder: "ansibleTestFolder1" + +- name: INSTALL PACKAGE + community.fortios.fmgr_fwpol_package: + mode: "set" + adom: "ansible" + name: "ansibleTestPackage1" + object_type: "install" + scope_members: "seattle-fgt03, seattle-fgt02" + +- name: REMOVE PACKAGE + community.fortios.fmgr_fwpol_package: + mode: "delete" + adom: "ansible" + name: "ansibleTestPackage1" + object_type: "pkg" + +- name: REMOVE NESTED PACKAGE + community.fortios.fmgr_fwpol_package: + mode: "delete" + adom: "ansible" + name: "ansibleTestPackage2" + object_type: "pkg" + parent_folder: "ansibleTestFolder1" + +- name: REMOVE NESTED FOLDER + community.fortios.fmgr_fwpol_package: + mode: "delete" + adom: "ansible" + name: "ansibleTestFolder2" + object_type: "folder" + parent_folder: "ansibleTestFolder1" + +- name: REMOVE FOLDER + community.fortios.fmgr_fwpol_package: + mode: "delete" + adom: "ansible" + name: "ansibleTestFolder1" + object_type: "folder" +''' +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods + + +def fmgr_fwpol_package(fmgr, paramgram): + """ + This function will create FMGR Firewall Policy Packages, or delete them. It is also capable of assigning packages. + This function DOES NOT install the package. See the function fmgr_fwpol_package_install() + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + if paramgram["mode"] in ['set', 'add']: + url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"]) + members_list = [] + + # CHECK FOR SCOPE MEMBERS AND CREATE THAT DICT + if paramgram["scope_members"] is not None: + members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"]) + for member in members: + scope_dict = { + "name": member, + "vdom": paramgram["scope_members_vdom"], + } + members_list.append(scope_dict) + + # IF PARENT FOLDER IS NOT DEFINED + if paramgram["parent_folder"] is None: + datagram = { + "type": paramgram["object_type"], + "name": paramgram["name"], + "scope member": members_list, + "package settings": { + "central-nat": paramgram["central-nat"], + "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"], + "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"], + "inspection-mode": paramgram["inspection-mode"], + "ngfw-mode": paramgram["ngfw-mode"], + } + } + + if paramgram["ngfw-mode"] == "policy-based" and paramgram["ssl-ssh-profile"] is not None: + datagram["package settings"]["ssl-ssh-profile"] = paramgram["ssl-ssh-profile"] + + # IF PARENT FOLDER IS DEFINED + if paramgram["parent_folder"] is not None: + datagram = { + "type": "folder", + "name": paramgram["parent_folder"], + "subobj": [{ + "name": paramgram["name"], + "scope member": members_list, + "type": "pkg", + "package settings": { + "central-nat": paramgram["central-nat"], + "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"], + "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"], + "inspection-mode": paramgram["inspection-mode"], + "ngfw-mode": paramgram["ngfw-mode"], + } + }] + } + + # NORMAL DELETE NO PARENT + if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None: + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"]) + + # DELETE WITH PARENT + if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None: + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"], + parent_folder=paramgram["parent_folder"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwpol_package_folder(fmgr, paramgram): + """ + This function will create folders for firewall packages. It can create down to two levels deep. + We haven't yet tested for any more layers below two levels. + parent_folders for multiple levels may need to defined as "level1/level2/level3" for the URL parameters and such. + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + if paramgram["mode"] in ['set', 'add']: + url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"]) + # IF PARENT FOLDER IS NOT DEFINED + if paramgram["parent_folder"] is None: + datagram = { + "type": paramgram["object_type"], + "name": paramgram["name"], + } + + # IF PARENT FOLDER IS DEFINED + if paramgram["parent_folder"] is not None: + datagram = { + "type": paramgram["object_type"], + "name": paramgram["parent_folder"], + "subobj": [{ + "name": paramgram["name"], + "type": paramgram["object_type"], + + }] + } + # NORMAL DELETE NO PARENT + if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None: + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"]) + + # DELETE WITH PARENT + if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None: + datagram = { + "name": paramgram["name"] + } + # SET DELETE URL + url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"], + parent_folder=paramgram["parent_folder"]) + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +def fmgr_fwpol_package_install(fmgr, paramgram): + """ + This method/function installs FMGR FW Policy Packages to the scope members defined in the playbook. + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + # INIT BLANK MEMBERS LIST + members_list = [] + # USE THE PARSE CSV FUNCTION TO GET A LIST FORMAT OF THE MEMBERS + members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"]) + # USE THAT LIST TO BUILD THE DICTIONARIES NEEDED, AND ADD TO THE BLANK MEMBERS LIST + for member in members: + scope_dict = { + "name": member, + "vdom": paramgram["scope_members_vdom"], + } + members_list.append(scope_dict) + # THEN FOR THE DATAGRAM, USING THE MEMBERS LIST CREATED ABOVE + datagram = { + "adom": paramgram["adom"], + "pkg": paramgram["name"], + "scope": members_list + } + # EXECUTE THE INSTALL REQUEST + url = '/securityconsole/install/package' + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "set", "delete"], type="str", default="add"), + + name=dict(required=False, type="str"), + object_type=dict(required=True, type="str", choices=['pkg', 'folder', 'install']), + package_folder=dict(required=False, type="str"), + central_nat=dict(required=False, type="str", default="disable", choices=['enable', 'disable']), + fwpolicy_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']), + fwpolicy6_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']), + inspection_mode=dict(required=False, type="str", default="flow", choices=['flow', 'proxy']), + ngfw_mode=dict(required=False, type="str", default="profile-based", choices=['profile-based', 'policy-based']), + ssl_ssh_profile=dict(required=False, type="str"), + scope_members=dict(required=False, type="str"), + scope_members_vdom=dict(required=False, type="str", default="root"), + parent_folder=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE DATAGRAM + paramgram = { + "adom": module.params["adom"], + "name": module.params["name"], + "mode": module.params["mode"], + "object_type": module.params["object_type"], + "package-folder": module.params["package_folder"], + "central-nat": module.params["central_nat"], + "fwpolicy-implicit-log": module.params["fwpolicy_implicit_log"], + "fwpolicy6-implicit-log": module.params["fwpolicy6_implicit_log"], + "inspection-mode": module.params["inspection_mode"], + "ngfw-mode": module.params["ngfw_mode"], + "ssl-ssh-profile": module.params["ssl_ssh_profile"], + "scope_members": module.params["scope_members"], + "scope_members_vdom": module.params["scope_members_vdom"], + "parent_folder": module.params["parent_folder"], + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION + results = DEFAULT_RESULT_OBJ + + try: + if paramgram["object_type"] == "pkg": + results = fmgr_fwpol_package(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF THE object_type IS FOLDER LETS RUN THAT METHOD + if paramgram["object_type"] == "folder": + results = fmgr_fwpol_package_folder(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF THE object_type IS INSTALL AND NEEDED PARAMETERS ARE DEFINED INSTALL THE PACKAGE + if paramgram["scope_members"] is not None and paramgram["name"] is not None and\ + paramgram["object_type"] == "install": + results = fmgr_fwpol_package_install(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py b/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py new file mode 100644 index 000000000..e24f11463 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py @@ -0,0 +1,349 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_ha +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manages the High-Availability State of FortiManager Clusters and Nodes. +description: Change HA state or settings of FortiManager nodes (Standalone/Master/Slave). + +options: + fmgr_ha_mode: + description: + - Sets the role of the FortiManager host for HA. + required: false + choices: ["standalone", "master", "slave"] + + fmgr_ha_peer_ipv4: + description: + - Sets the IPv4 address of a HA peer. + required: false + + fmgr_ha_peer_ipv6: + description: + - Sets the IPv6 address of a HA peer. + required: false + + fmgr_ha_peer_sn: + description: + - Sets the HA Peer Serial Number. + required: false + + fmgr_ha_peer_status: + description: + - Sets the peer status to enable or disable. + required: false + choices: ["enable", "disable"] + + fmgr_ha_cluster_pw: + description: + - Sets the password for the HA cluster. Only required once. System remembers between HA mode switches. + required: false + + fmgr_ha_cluster_id: + description: + - Sets the ID number of the HA cluster. Defaults to 1. + required: false + default: 1 + + fmgr_ha_hb_threshold: + description: + - Sets heartbeat lost threshold (1-255). + required: false + default: 3 + + fmgr_ha_hb_interval: + description: + - Sets the heartbeat interval (1-255). + required: false + default: 5 + + fmgr_ha_file_quota: + description: + - Sets the File quota in MB (2048-20480). + required: false + default: 4096 +''' + + +EXAMPLES = ''' +- name: SET FORTIMANAGER HA NODE TO MASTER + community.fortios.fmgr_ha: + fmgr_ha_mode: "master" + fmgr_ha_cluster_pw: "fortinet" + fmgr_ha_cluster_id: "1" + +- name: SET FORTIMANAGER HA NODE TO SLAVE + community.fortios.fmgr_ha: + fmgr_ha_mode: "slave" + fmgr_ha_cluster_pw: "fortinet" + fmgr_ha_cluster_id: "1" + +- name: SET FORTIMANAGER HA NODE TO STANDALONE + community.fortios.fmgr_ha: + fmgr_ha_mode: "standalone" + +- name: ADD FORTIMANAGER HA PEER + community.fortios.fmgr_ha: + fmgr_ha_peer_ipv4: "192.168.1.254" + fmgr_ha_peer_sn: "FMG-VM1234567890" + fmgr_ha_peer_status: "enable" + +- name: CREATE CLUSTER ON MASTER + community.fortios.fmgr_ha: + fmgr_ha_mode: "master" + fmgr_ha_cluster_pw: "fortinet" + fmgr_ha_cluster_id: "1" + fmgr_ha_hb_threshold: "10" + fmgr_ha_hb_interval: "15" + fmgr_ha_file_quota: "2048" +''' +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def fmgr_set_ha_mode(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + if paramgram["fmgr_ha_cluster_pw"] is not None and str(paramgram["fmgr_ha_mode"].lower()) != "standalone": + datagram = { + "mode": paramgram["fmgr_ha_mode"], + "file-quota": paramgram["fmgr_ha_file_quota"], + "hb-interval": paramgram["fmgr_ha_hb_interval"], + "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"], + "password": paramgram["fmgr_ha_cluster_pw"], + "clusterid": paramgram["fmgr_ha_cluster_id"] + } + elif str(paramgram["fmgr_ha_mode"].lower()) == "standalone": + datagram = { + "mode": paramgram["fmgr_ha_mode"], + "file-quota": paramgram["fmgr_ha_file_quota"], + "hb-interval": paramgram["fmgr_ha_hb_interval"], + "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"], + "clusterid": paramgram["fmgr_ha_cluster_id"] + } + + url = '/cli/global/system/ha' + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + return response + + +def fmgr_get_ha_peer_list(fmgr): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + + datagram = {} + paramgram = {} + + url = '/cli/global/system/ha/peer/' + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + return response + + +def fmgr_set_ha_peer(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + "ip": paramgram["fmgr_ha_peer_ipv4"], + "ip6": paramgram["fmgr_ha_peer_ipv6"], + "serial-number": paramgram["fmgr_ha_peer_sn"], + "status": paramgram["fmgr_ha_peer_status"], + "id": paramgram["peer_id"] + } + + url = '/cli/global/system/ha/peer/' + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + return response + + +def main(): + argument_spec = dict( + fmgr_ha_mode=dict(required=False, type="str", choices=["standalone", "master", "slave"]), + fmgr_ha_cluster_pw=dict(required=False, type="str", no_log=True), + fmgr_ha_peer_status=dict(required=False, type="str", choices=["enable", "disable"]), + fmgr_ha_peer_sn=dict(required=False, type="str"), + fmgr_ha_peer_ipv4=dict(required=False, type="str"), + fmgr_ha_peer_ipv6=dict(required=False, type="str"), + fmgr_ha_hb_threshold=dict(required=False, type="int", default=3), + fmgr_ha_hb_interval=dict(required=False, type="int", default=5), + fmgr_ha_file_quota=dict(required=False, type="int", default=4096), + fmgr_ha_cluster_id=dict(required=False, type="int", default=1) + ) + + required_if = [ + ['fmgr_ha_peer_ipv4', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']], + ['fmgr_ha_peer_ipv6', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']], + ['fmgr_ha_mode', 'master', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']], + ['fmgr_ha_mode', 'slave', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']], + ] + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_if=required_if) + paramgram = { + "fmgr_ha_mode": module.params["fmgr_ha_mode"], + "fmgr_ha_cluster_pw": module.params["fmgr_ha_cluster_pw"], + "fmgr_ha_peer_status": module.params["fmgr_ha_peer_status"], + "fmgr_ha_peer_sn": module.params["fmgr_ha_peer_sn"], + "fmgr_ha_peer_ipv4": module.params["fmgr_ha_peer_ipv4"], + "fmgr_ha_peer_ipv6": module.params["fmgr_ha_peer_ipv6"], + "fmgr_ha_hb_threshold": module.params["fmgr_ha_hb_threshold"], + "fmgr_ha_hb_interval": module.params["fmgr_ha_hb_interval"], + "fmgr_ha_file_quota": module.params["fmgr_ha_file_quota"], + "fmgr_ha_cluster_id": module.params["fmgr_ha_cluster_id"], + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + # INIT FLAGS AND COUNTERS + get_ha_peers = 0 + results = DEFAULT_RESULT_OBJ + try: + if any(v is not None for v in (paramgram["fmgr_ha_peer_sn"], paramgram["fmgr_ha_peer_ipv4"], + paramgram["fmgr_ha_peer_ipv6"], paramgram["fmgr_ha_peer_status"])): + get_ha_peers = 1 + except Exception as err: + raise FMGBaseException(err) + try: + # IF HA MODE IS NOT NULL, SWITCH THAT + if paramgram["fmgr_ha_mode"] is not None: + if (str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and paramgram["fmgr_ha_cluster_pw"] is not None)\ + or str.lower(paramgram["fmgr_ha_mode"]) == "standalone": + results = fmgr_set_ha_mode(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, stop_on_success=False, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + elif str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and\ + paramgram["fmgr_ha_mode"] is not None and\ + paramgram["fmgr_ha_cluster_pw"] is None: + module.exit_json(msg="If setting HA Mode of MASTER or SLAVE, you must specify a cluster password") + + except Exception as err: + raise FMGBaseException(err) + # IF GET_HA_PEERS IS ENABLED, LETS PROCESS THE PEERS + try: + if get_ha_peers == 1: + # GET THE CURRENT LIST OF PEERS FROM THE NODE + peers = fmgr_get_ha_peer_list(fmgr) + # GET LENGTH OF RETURNED PEERS LIST AND ADD ONE FOR THE NEXT ID + paramgram["next_peer_id"] = len(peers[1]) + 1 + # SET THE ACTUAL NUMBER OF PEERS + num_of_peers = len(peers[1]) + # SET THE PEER ID FOR DISABLE METHOD + paramgram["peer_id"] = len(peers) - 1 + # SET THE PEER LOOPCOUNT TO 1 TO START THE LOOP + peer_loopcount = 1 + + # LOOP THROUGH PEERS TO FIND THE SERIAL NUMBER MATCH TO GET THE RIGHT PEER ID + # IDEA BEING WE DON'T WANT TO SUBMIT A BAD peer_id THAT DOESN'T JIVE WITH CURRENT DB ON FMG + # SO LETS SEARCH FOR IT, AND IF WE FIND IT, WE WILL CHANGE THE PEER ID VARIABLES TO MATCH + # IF NOT FOUND, LIFE GOES ON AND WE ASSUME THAT WE'RE ADDING A PEER + # AT WHICH POINT THE next_peer_id VARIABLE WILL HAVE THE RIGHT PRIMARY KEY + + if paramgram["fmgr_ha_peer_sn"] is not None: + while peer_loopcount <= num_of_peers: + # GET THE SERIAL NUMBER FOR CURRENT PEER IN LOOP TO COMPARE TO SN IN PLAYBOOK + try: + sn_compare = peers[1][peer_loopcount - 1]["serial-number"] + # IF THE SN IN THE PEERS MATCHES THE PLAYBOOK SN, SET THE IDS + if sn_compare == paramgram["fmgr_ha_peer_sn"]: + paramgram["peer_id"] = peer_loopcount + paramgram["next_peer_id"] = paramgram["peer_id"] + except Exception as err: + raise FMGBaseException(err) + # ADVANCE THE LOOP AND REPEAT UNTIL DONE + peer_loopcount += 1 + + # IF THE PEER STATUS ISN'T IN THE PLAYBOOK, ASSUME ITS ENABLE + if paramgram["fmgr_ha_peer_status"] is None: + paramgram["fmgr_ha_peer_status"] = "enable" + + # IF THE PEER STATUS IS ENABLE, USE THE next_peer_id IN THE API CALL FOR THE ID + if paramgram["fmgr_ha_peer_status"] == "enable": + results = fmgr_set_ha_peer(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, stop_on_success=True, + ansible_facts=fmgr.construct_ansible_facts(results, + module.params, paramgram)) + + # IF THE PEER STATUS IS DISABLE, WE HAVE TO HANDLE THAT A BIT DIFFERENTLY + # JUST USING TWO DIFFERENT peer_id 's HERE + if paramgram["fmgr_ha_peer_status"] == "disable": + results = fmgr_set_ha_peer(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, stop_on_success=True, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py b/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py new file mode 100644 index 000000000..da499cbe4 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py @@ -0,0 +1,360 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_provisioning +author: Andrew Welsh (@Ghilli3) +short_description: Provision devices via FortiMananger +description: + - Add model devices on the FortiManager using jsonrpc API and have them pre-configured, + so when central management is configured, the configuration is pushed down to the + registering devices + +options: + adom: + description: + - The administrative domain (admon) the configuration belongs to + required: true + vdom: + description: + - The virtual domain (vdom) the configuration belongs to + host: + description: + - The FortiManager's Address. + required: true + username: + description: + - The username to log into the FortiManager + required: true + password: + description: + - The password associated with the username account. + required: false + + policy_package: + description: + - The name of the policy package to be assigned to the device. + required: True + name: + description: + - The name of the device to be provisioned. + required: True + group: + description: + - The name of the device group the provisioned device can belong to. + required: False + serial: + description: + - The serial number of the device that will be provisioned. + required: True + platform: + description: + - The platform of the device, such as model number or VM. + required: True + description: + description: + - Description of the device to be provisioned. + required: False + os_version: + description: + - The Fortinet OS version to be used for the device, such as 5.0 or 6.0. + required: True + minor_release: + description: + - The minor release number such as 6.X.1, as X being the minor release. + required: False + patch_release: + description: + - The patch release number such as 6.0.X, as X being the patch release. + required: False + os_type: + description: + - The Fortinet OS type to be pushed to the device, such as 'FOS' for FortiOS. + required: True +''' + +EXAMPLES = ''' +- name: Create FGT1 Model Device + community.fortios.fmgr_provisioning: + host: "{{ inventory_hostname }}" + username: "{{ username }}" + password: "{{ password }}" + adom: "root" + vdom: "root" + policy_package: "default" + name: "FGT1" + group: "Ansible" + serial: "FGVM000000117994" + platform: "FortiGate-VM64" + description: "Provisioned by Ansible" + os_version: '6.0' + minor_release: 0 + patch_release: 0 + os_type: 'fos' + + +- name: Create FGT2 Model Device + community.fortios.fmgr_provisioning: + host: "{{ inventory_hostname }}" + username: "{{ username }}" + password: "{{ password }}" + adom: "root" + vdom: "root" + policy_package: "test_pp" + name: "FGT2" + group: "Ansible" + serial: "FGVM000000117992" + platform: "FortiGate-VM64" + description: "Provisioned by Ansible" + os_version: '5.0' + minor_release: 6 + patch_release: 0 + os_type: 'fos' + +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import AnsibleFortiManager + +# check for pyFMG lib +try: + from pyFMG.fortimgr import FortiManager + HAS_PYFMGR = True +except ImportError: + HAS_PYFMGR = False + + +def dev_group_exists(fmg, dev_grp_name, adom): + datagram = { + 'adom': adom, + 'name': dev_grp_name, + } + + url = '/dvmdb/adom/{adom}/group/{dev_grp_name}'.format(adom=adom, dev_grp_name=dev_grp_name) + response = fmg.get(url, datagram) + return response + + +def prov_template_exists(fmg, prov_template, adom, vdom): + datagram = { + 'name': prov_template, + 'adom': adom, + } + + url = '/pm/devprof/adom/{adom}/devprof/{name}'.format(adom=adom, name=prov_template) + response = fmg.get(url, datagram) + return response + + +def create_model_device(fmg, name, serial, group, platform, os_version, + os_type, minor_release, patch_release=0, adom='root'): + datagram = { + 'adom': adom, + 'flags': ['create_task', 'nonblocking'], + 'groups': [{'name': group, 'vdom': 'root'}], + 'device': { + 'mr': minor_release, + 'name': name, + 'sn': serial, + 'mgmt_mode': 'fmg', + 'device action': 'add_model', + 'platform_str': platform, + 'os_ver': os_version, + 'os_type': os_type, + 'patch': patch_release, + 'desc': 'Provisioned by Ansible', + } + } + + url = '/dvm/cmd/add/device' + response = fmg.execute(url, datagram) + return response + + +def update_flags(fmg, name): + datagram = { + 'flags': ['is_model', 'linked_to_model'] + } + url = 'dvmdb/device/{name}'.format(name=name) + response = fmg.update(url, datagram) + return response + + +def assign_provision_template(fmg, template, adom, target): + datagram = { + 'name': template, + 'type': 'devprof', + 'description': 'Provisioned by Ansible', + 'scope member': [{'name': target}] + } + url = "/pm/devprof/adom/{adom}".format(adom=adom) + response = fmg.update(url, datagram) + return response + + +def set_devprof_scope(self, provisioning_template, adom, provision_targets): + """ + GET the DevProf (check to see if exists) + """ + fields = dict() + targets = [] + fields["name"] = provisioning_template + fields["type"] = "devprof" + fields["description"] = "CreatedByAnsible" + + for target in provision_targets.strip().split(","): + # split the host on the space to get the mask out + new_target = {"name": target} + targets.append(new_target) + + fields["scope member"] = targets + + body = {"method": "set", "params": [{"url": "/pm/devprof/adom/{adom}".format(adom=adom), + "data": fields, "session": self.session}]} + response = self.make_request(body).json() + return response + + +def assign_dev_grp(fmg, grp_name, device_name, vdom, adom): + datagram = { + 'name': device_name, + 'vdom': vdom, + } + url = "/dvmdb/adom/{adom}/group/{grp_name}/object member".format(adom=adom, grp_name=grp_name) + response = fmg.set(url, datagram) + return response + + +def update_install_target(fmg, device, pp='default', vdom='root', adom='root'): + datagram = { + 'scope member': [{'name': device, 'vdom': vdom}], + 'type': 'pkg' + } + url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=adom, pkg_name=pp) + response = fmg.update(url, datagram) + return response + + +def install_pp(fmg, device, pp='default', vdom='root', adom='root'): + datagram = { + 'adom': adom, + 'flags': 'nonblocking', + 'pkg': pp, + 'scope': [{'name': device, 'vdom': vdom}], + } + url = 'securityconsole/install/package' + response = fmg.execute(url, datagram) + return response + + +def main(): + + argument_spec = dict( + adom=dict(required=False, type="str"), + vdom=dict(required=False, type="str"), + host=dict(required=True, type="str"), + password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True), + username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True), + + policy_package=dict(required=False, type="str"), + name=dict(required=False, type="str"), + group=dict(required=False, type="str"), + serial=dict(required=True, type="str"), + platform=dict(required=True, type="str"), + description=dict(required=False, type="str"), + os_version=dict(required=True, type="str"), + minor_release=dict(required=False, type="str"), + patch_release=dict(required=False, type="str"), + os_type=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec, supports_check_mode=True, ) + + # check if params are set + if module.params["host"] is None or module.params["username"] is None: + module.fail_json(msg="Host and username are required for connection") + + # check if login failed + fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"]) + response = fmg.login() + + if "FortiManager instance connnected" not in str(response): + module.fail_json(msg="Connection to FortiManager Failed") + else: + + if module.params["policy_package"] is None: + module.params["policy_package"] = 'default' + if module.params["adom"] is None: + module.params["adom"] = 'root' + if module.params["vdom"] is None: + module.params["vdom"] = 'root' + if module.params["platform"] is None: + module.params["platform"] = 'FortiGate-VM64' + if module.params["os_type"] is None: + module.params["os_type"] = 'fos' + + results = create_model_device(fmg, + module.params["name"], + module.params["serial"], + module.params["group"], + module.params["platform"], + module.params["os_ver"], + module.params["os_type"], + module.params["minor_release"], + module.params["patch_release"], + module.params["adom"]) + if results[0] != 0: + module.fail_json(msg="Create model failed", **results) + + results = update_flags(fmg, module.params["name"]) + if results[0] != 0: + module.fail_json(msg="Update device flags failed", **results) + + # results = assign_dev_grp(fmg, 'Ansible', 'FGVM000000117992', 'root', 'root') + # if not results[0] == 0: + # module.fail_json(msg="Setting device group failed", **results) + + results = update_install_target(fmg, module.params["name"], module.params["policy_package"]) + if results[0] != 0: + module.fail_json(msg="Adding device target to package failed", **results) + + results = install_pp(fmg, module.params["name"], module.params["policy_package"]) + if results[0] != 0: + module.fail_json(msg="Installing policy package failed", **results) + + fmg.logout() + + # results is returned as a tuple + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_query.py b/ansible_collections/community/fortios/plugins/modules/fmgr_query.py new file mode 100644 index 000000000..1ceb7dbb3 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_query.py @@ -0,0 +1,424 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_query +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: Luke Weighall (@lweighall) +short_description: Query FortiManager data objects for use in Ansible workflows. +description: + - Provides information on data objects within FortiManager so that playbooks can perform conditionals. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + object: + description: + - The data object we wish to query (device, package, rule, etc). Will expand choices as improves. + required: true + choices: + - device + - cluster_nodes + - task + - custom + + custom_endpoint: + description: + - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API! + - The HTTP Endpoint on FortiManager you wish to GET from. + required: false + + custom_dict: + description: + - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API! + - DICTIONARY JSON FORMAT ONLY -- Custom dictionary/datagram to send to the endpoint. + required: false + + device_ip: + description: + - The IP of the device you want to query. + required: false + + device_unique_name: + description: + - The desired "friendly" name of the device you want to query. + required: false + + device_serial: + description: + - The serial number of the device you want to query. + required: false + + task_id: + description: + - The ID of the task you wish to query status on. If left blank and object = 'task' a list of tasks are returned. + required: false + + nodes: + description: + - A LIST of firewalls in the cluster you want to verify i.e. ["firewall_A","firewall_B"]. + required: false +''' + + +EXAMPLES = ''' +- name: QUERY FORTIGATE DEVICE BY IP + community.fortios.fmgr_query: + object: "device" + adom: "ansible" + device_ip: "10.7.220.41" + +- name: QUERY FORTIGATE DEVICE BY SERIAL + community.fortios.fmgr_query: + adom: "ansible" + object: "device" + device_serial: "FGVM000000117992" + +- name: QUERY FORTIGATE DEVICE BY FRIENDLY NAME + community.fortios.fmgr_query: + adom: "ansible" + object: "device" + device_unique_name: "ansible-fgt01" + +- name: VERIFY CLUSTER MEMBERS AND STATUS + community.fortios.fmgr_query: + adom: "ansible" + object: "cluster_nodes" + device_unique_name: "fgt-cluster01" + nodes: ["ansible-fgt01", "ansible-fgt02", "ansible-fgt03"] + +- name: GET STATUS OF TASK ID + community.fortios.fmgr_query: + adom: "ansible" + object: "task" + task_id: "3" + +- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS + community.fortios.fmgr_query: + adom: "ansible" + object: "custom" + custom_endpoint: "/dvmdb/adom/ansible/script" + custom_dict: { "type": "cli" } +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def fmgr_get_custom(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT + if paramgram["custom_dict"] is not None: + datagram = paramgram["custom_dict"] + else: + datagram = dict() + + # SET THE CUSTOM ENDPOINT PROVIDED + url = paramgram["custom_endpoint"] + # MAKE THE CALL AND RETURN RESULTS + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + return response + + +def fmgr_get_task_status(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK + # OTHERWISE, GET ALL RECENT TASKS IN A LIST + if paramgram["task_id"] is not None: + + datagram = { + "adom": paramgram["adom"] + } + url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"]) + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + else: + datagram = { + "adom": paramgram["adom"] + } + url = '/task/task' + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + return response + + +def fmgr_get_device(fmgr, paramgram): + """ + This method is used to get information on devices. This will not work on HA_SLAVE nodes, only top level devices. + Such as cluster objects and standalone devices. + + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + # FIRST TRY TO RUN AN UPDATE ON THE DEVICE + # RUN A QUICK CLUSTER REFRESH/UPDATE ATTEMPT TO ENSURE WE'RE GETTING THE LATEST INFORMOATION + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + update_url = '/dvm/cmd/update/device' + update_dict = { + "adom": paramgram['adom'], + "device": paramgram['device_unique_name'], + "flags": "create_task" + } + # DO THE UPDATE CALL + fmgr.process_request(update_url, update_dict, FMGRMethods.EXEC) + + # SET THE URL + url = '/dvmdb/adom/{adom}/device'.format(adom=paramgram["adom"]) + device_found = 0 + response = [] + + # TRY TO FIND IT FIRST BY SERIAL NUMBER + if paramgram["device_serial"] is not None: + datagram = { + "filter": ["sn", "==", paramgram["device_serial"]] + } + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + if len(response[1]) >= 0: + device_found = 1 + + # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE NAME PARAMETER + if device_found == 0 and paramgram["device_unique_name"] is not None: + datagram = { + "filter": ["name", "==", paramgram["device_unique_name"]] + } + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + if len(response[1]) >= 0: + device_found = 1 + + # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE IP ADDRESS + if device_found == 0 and paramgram["device_ip"] is not None: + datagram = { + "filter": ["ip", "==", paramgram["device_ip"]] + } + response = fmgr.process_request(url, datagram, FMGRMethods.GET) + if len(response[1]) >= 0: + device_found = 1 + + return response + + +def fmgr_get_cluster_nodes(fmgr, paramgram): + """ + This method is used to get information on devices. This WILL work on HA_SLAVE nodes, but NOT top level standalone + devices. + Such as cluster objects and standalone devices. + + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + # USE THE DEVICE METHOD TO GET THE CLUSTER INFORMATION SO WE CAN SEE THE HA_SLAVE NODES + response = fmgr_get_device(fmgr, paramgram) + # CHECK FOR HA_SLAVE NODES, IF CLUSTER IS MISSING COMPLETELY THEN QUIT + try: + returned_nodes = response[1][0]["ha_slave"] + num_of_nodes = len(returned_nodes) + except Exception: + error_msg = {"cluster_status": "MISSING"} + return error_msg + + # INIT LOOP RESOURCES + loop_count = 0 + good_nodes = [] + expected_nodes = list(paramgram["nodes"]) + missing_nodes = list(paramgram["nodes"]) + bad_status_nodes = [] + + # LOOP THROUGH THE NODES AND GET THEIR STATUS TO BUILD THE RETURN JSON OBJECT + # WE'RE ALSO CHECKING THE NODES IF THEY ARE BAD STATUS, OR PLAIN MISSING + while loop_count < num_of_nodes: + node_append = { + "node_name": returned_nodes[loop_count]["name"], + "node_serial": returned_nodes[loop_count]["sn"], + "node_parent": returned_nodes[loop_count]["did"], + "node_status": returned_nodes[loop_count]["status"], + } + # IF THE NODE IS IN THE EXPECTED NODES LIST AND WORKING THEN ADD IT TO GOOD NODES LIST + if node_append["node_name"] in expected_nodes and node_append["node_status"] == 1: + good_nodes.append(node_append["node_name"]) + # IF THE NODE IS IN THE EXPECTED NODES LIST BUT NOT WORKING THEN ADDED IT TO BAD_STATUS_NODES + # IF THE NODE STATUS IS NOT 1 THEN ITS BAD + if node_append["node_name"] in expected_nodes and node_append["node_status"] != 1: + bad_status_nodes.append(node_append["node_name"]) + # REMOVE THE NODE FROM MISSING NODES LIST IF NOTHING IS WRONG WITH NODE -- LEAVING US A LIST OF + # NOT WORKING NODES + missing_nodes.remove(node_append["node_name"]) + loop_count += 1 + + # BUILD RETURN OBJECT FROM NODE LISTS + nodes = { + "good_nodes": good_nodes, + "expected_nodes": expected_nodes, + "missing_nodes": missing_nodes, + "bad_nodes": bad_status_nodes, + "query_status": "good", + } + if len(nodes["good_nodes"]) == len(nodes["expected_nodes"]): + nodes["cluster_status"] = "OK" + else: + nodes["cluster_status"] = "NOT-COMPLIANT" + return nodes + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + object=dict(required=True, type="str", choices=["device", "cluster_nodes", "task", "custom"]), + custom_endpoint=dict(required=False, type="str"), + custom_dict=dict(required=False, type="dict"), + device_ip=dict(required=False, type="str"), + device_unique_name=dict(required=False, type="str"), + device_serial=dict(required=False, type="str"), + nodes=dict(required=False, type="list"), + task_id=dict(required=False, type="str") + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + paramgram = { + "adom": module.params["adom"], + "object": module.params["object"], + "device_ip": module.params["device_ip"], + "device_unique_name": module.params["device_unique_name"], + "device_serial": module.params["device_serial"], + "nodes": module.params["nodes"], + "task_id": module.params["task_id"], + "custom_endpoint": module.params["custom_endpoint"], + "custom_dict": module.params["custom_dict"] + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + + try: + # IF OBJECT IS DEVICE + if paramgram["object"] == "device" and any(v is not None for v in [paramgram["device_unique_name"], + paramgram["device_serial"], + paramgram["device_ip"]]): + results = fmgr_get_device(fmgr, paramgram) + if results[0] not in [0]: + module.fail_json(msg="Device query failed!") + elif len(results[1]) == 0: + module.exit_json(msg="Device NOT FOUND!") + else: + module.exit_json(msg="Device Found", **results[1][0]) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT IS CLUSTER_NODES + if paramgram["object"] == "cluster_nodes" and paramgram["nodes"] is not None: + results = fmgr_get_cluster_nodes(fmgr, paramgram) + if results["cluster_status"] == "MISSING": + module.exit_json(msg="No cluster device found!", **results) + elif results["query_status"] == "good": + module.exit_json(msg="Cluster Found - Showing Nodes", **results) + elif results is None: + module.fail_json(msg="Query FAILED -- Check module or playbook syntax") + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT IS TASK + if paramgram["object"] == "task": + results = fmgr_get_task_status(fmgr, paramgram) + if results[0] != 0: + module.fail_json(**results[1]) + if results[0] == 0: + module.exit_json(**results[1]) + except Exception as err: + raise FMGBaseException(err) + + try: + # IF OBJECT IS CUSTOM + if paramgram["object"] == "custom": + results = fmgr_get_custom(fmgr, paramgram) + if results[0] != 0: + module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.") + if results[0] == 0: + results_len = len(results[1]) + if results_len > 0: + results_combine = dict() + if isinstance(results[1], dict): + results_combine["results"] = results[1] + if isinstance(results[1], list): + results_combine["results"] = results[1][0:results_len] + module.exit_json(msg="Custom Query Success", **results_combine) + else: + module.exit_json(msg="NO RESULTS") + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_script.py b/ansible_collections/community/fortios/plugins/modules/fmgr_script.py new file mode 100644 index 000000000..d84606cce --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_script.py @@ -0,0 +1,262 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_script +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: Andrew Welsh (@Ghilli3) +short_description: Add/Edit/Delete and execute scripts +description: Create/edit/delete scripts and execute the scripts on the FortiManager using jsonrpc API + +options: + adom: + description: + - The administrative domain (admon) the configuration belongs to + required: true + + vdom: + description: + - The virtual domain (vdom) the configuration belongs to + + mode: + description: + - The desired mode of the specified object. Execute will run the script. + required: false + default: "add" + choices: ["add", "delete", "execute", "set"] + + script_name: + description: + - The name of the script. + required: True + + script_type: + description: + - The type of script (CLI or TCL). + required: false + + script_target: + description: + - The target of the script to be run. + required: false + + script_description: + description: + - The description of the script. + required: false + + script_content: + description: + - The script content that will be executed. + required: false + + script_scope: + description: + - (datasource) The devices that the script will run on, can have both device member and device group member. + required: false + + script_package: + description: + - (datasource) Policy package object to run the script against + required: false +''' + +EXAMPLES = ''' +- name: CREATE SCRIPT + community.fortios.fmgr_script: + adom: "root" + script_name: "TestScript" + script_type: "cli" + script_target: "remote_device" + script_description: "Create by Ansible" + script_content: "get system status" + +- name: EXECUTE SCRIPT + community.fortios.fmgr_script: + adom: "root" + script_name: "TestScript" + mode: "execute" + script_scope: "FGT1,FGT2" + +- name: DELETE SCRIPT + community.fortios.fmgr_script: + adom: "root" + script_name: "TestScript" + mode: "delete" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG + + +def set_script(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + 'content': paramgram["script_content"], + 'desc': paramgram["script_description"], + 'name': paramgram["script_name"], + 'target': paramgram["script_target"], + 'type': paramgram["script_type"], + } + + url = '/dvmdb/adom/{adom}/script/'.format(adom=paramgram["adom"]) + response = fmgr.process_request(url, datagram, FMGRMethods.SET) + return response + + +def delete_script(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + datagram = { + 'name': paramgram["script_name"], + } + + url = '/dvmdb/adom/{adom}/script/{script_name}'.format(adom=paramgram["adom"], script_name=paramgram["script_name"]) + response = fmgr.process_request(url, datagram, FMGRMethods.DELETE) + return response + + +def execute_script(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + scope_list = list() + scope = paramgram["script_scope"].replace(' ', '') + scope = scope.split(',') + for dev_name in scope: + scope_list.append({'name': dev_name, 'vdom': paramgram["vdom"]}) + + datagram = { + 'adom': paramgram["adom"], + 'script': paramgram["script_name"], + 'package': paramgram["script_package"], + 'scope': scope_list, + } + + url = '/dvmdb/adom/{adom}/script/execute'.format(adom=paramgram["adom"]) + response = fmgr.process_request(url, datagram, FMGRMethods.EXEC) + return response + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + vdom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "execute", "set", "delete"], type="str", default="add"), + script_name=dict(required=True, type="str"), + script_type=dict(required=False, type="str"), + script_target=dict(required=False, type="str"), + script_description=dict(required=False, type="str"), + script_content=dict(required=False, type="str"), + script_scope=dict(required=False, type="str"), + script_package=dict(required=False, type="str"), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + paramgram = { + "script_name": module.params["script_name"], + "script_type": module.params["script_type"], + "script_target": module.params["script_target"], + "script_description": module.params["script_description"], + "script_content": module.params["script_content"], + "script_scope": module.params["script_scope"], + "script_package": module.params["script_package"], + "adom": module.params["adom"], + "vdom": module.params["vdom"], + "mode": module.params["mode"], + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + + try: + if paramgram["mode"] in ['add', 'set']: + results = set_script(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, msg="Operation Finished", + ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params)) + except Exception as err: + raise FMGBaseException(err) + + try: + if paramgram["mode"] == "execute": + results = execute_script(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, msg="Operation Finished", + ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params)) + except Exception as err: + raise FMGBaseException(err) + + try: + if paramgram["mode"] == "delete": + results = delete_script(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, msg="Operation Finished", + ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py new file mode 100644 index 000000000..aabd29859 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py @@ -0,0 +1,516 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_appctrl +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage application control security profiles +description: + - Manage application control security profiles within FortiManager + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + unknown_application_log: + description: + - Enable/disable logging for unknown applications. + - choice | disable | Disable logging for unknown applications. + - choice | enable | Enable logging for unknown applications. + required: false + choices: ["disable", "enable"] + + unknown_application_action: + description: + - Pass or block traffic from unknown applications. + - choice | pass | Pass or allow unknown applications. + - choice | block | Drop or block unknown applications. + required: false + choices: ["pass", "block"] + + replacemsg_group: + description: + - Replacement message group. + required: false + + p2p_black_list: + description: + - NO DESCRIPTION PARSED ENTER MANUALLY + - FLAG Based Options. Specify multiple in list form. + - flag | skype | Skype. + - flag | edonkey | Edonkey. + - flag | bittorrent | Bit torrent. + required: false + choices: ["skype", "edonkey", "bittorrent"] + + other_application_log: + description: + - Enable/disable logging for other applications. + - choice | disable | Disable logging for other applications. + - choice | enable | Enable logging for other applications. + required: false + choices: ["disable", "enable"] + + other_application_action: + description: + - Action for other applications. + - choice | pass | Allow sessions matching an application in this application list. + - choice | block | Block sessions matching an application in this application list. + required: false + choices: ["pass", "block"] + + options: + description: + - NO DESCRIPTION PARSED ENTER MANUALLY + - FLAG Based Options. Specify multiple in list form. + - flag | allow-dns | Allow DNS. + - flag | allow-icmp | Allow ICMP. + - flag | allow-http | Allow generic HTTP web browsing. + - flag | allow-ssl | Allow generic SSL communication. + - flag | allow-quic | Allow QUIC. + required: false + choices: ["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"] + + name: + description: + - List name. + required: false + + extended_log: + description: + - Enable/disable extended logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + deep_app_inspection: + description: + - Enable/disable deep application inspection. + - choice | disable | Disable deep application inspection. + - choice | enable | Enable deep application inspection. + required: false + choices: ["disable", "enable"] + + comment: + description: + - comments + required: false + + app_replacemsg: + description: + - Enable/disable replacement messages for blocked applications. + - choice | disable | Disable replacement messages for blocked applications. + - choice | enable | Enable replacement messages for blocked applications. + required: false + choices: ["disable", "enable"] + + entries: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, OMIT THE USE OF THIS PARAMETER + - AND USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + entries_action: + description: + - Pass or block traffic, or reset connection for traffic from this application. + - choice | pass | Pass or allow matching traffic. + - choice | block | Block or drop matching traffic. + - choice | reset | Reset sessions for matching traffic. + required: false + choices: ["pass", "block", "reset"] + + entries_application: + description: + - ID of allowed applications. + required: false + + entries_behavior: + description: + - Application behavior filter. + required: false + + entries_category: + description: + - Category ID list. + required: false + + entries_log: + description: + - Enable/disable logging for this application list. + - choice | disable | Disable logging. + - choice | enable | Enable logging. + required: false + choices: ["disable", "enable"] + + entries_log_packet: + description: + - Enable/disable packet logging. + - choice | disable | Disable packet logging. + - choice | enable | Enable packet logging. + required: false + choices: ["disable", "enable"] + + entries_per_ip_shaper: + description: + - Per-IP traffic shaper. + required: false + + entries_popularity: + description: + - Application popularity filter (1 - 5, from least to most popular). + - FLAG Based Options. Specify multiple in list form. + - flag | 1 | Popularity level 1. + - flag | 2 | Popularity level 2. + - flag | 3 | Popularity level 3. + - flag | 4 | Popularity level 4. + - flag | 5 | Popularity level 5. + required: false + choices: ["1", "2", "3", "4", "5"] + + entries_protocols: + description: + - Application protocol filter. + required: false + + entries_quarantine: + description: + - Quarantine method. + - choice | none | Quarantine is disabled. + - choice | attacker | Block all traffic sent from attacker's IP address. + - The attacker's IP address is also added to the banned user list. The target's address is not affected. + required: false + choices: ["none", "attacker"] + + entries_quarantine_expiry: + description: + - Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m). + - Requires quarantine set to attacker. + required: false + + entries_quarantine_log: + description: + - Enable/disable quarantine logging. + - choice | disable | Disable quarantine logging. + - choice | enable | Enable quarantine logging. + required: false + choices: ["disable", "enable"] + + entries_rate_count: + description: + - Count of the rate. + required: false + + entries_rate_duration: + description: + - Duration (sec) of the rate. + required: false + + entries_rate_mode: + description: + - Rate limit mode. + - choice | periodical | Allow configured number of packets every rate-duration. + - choice | continuous | Block packets once the rate is reached. + required: false + choices: ["periodical", "continuous"] + + entries_rate_track: + description: + - Track the packet protocol field. + - choice | none | + - choice | src-ip | Source IP. + - choice | dest-ip | Destination IP. + - choice | dhcp-client-mac | DHCP client. + - choice | dns-domain | DNS domain. + required: false + choices: ["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"] + + entries_risk: + description: + - Risk, or impact, of allowing traffic from this application to occur 1 - 5; + - (Low, Elevated, Medium, High, and Critical). + required: false + + entries_session_ttl: + description: + - Session TTL (0 = default). + required: false + + entries_shaper: + description: + - Traffic shaper. + required: false + + entries_shaper_reverse: + description: + - Reverse traffic shaper. + required: false + + entries_sub_category: + description: + - Application Sub-category ID list. + required: false + + entries_technology: + description: + - Application technology filter. + required: false + + entries_vendor: + description: + - Application vendor filter. + required: false + + entries_parameters_value: + description: + - Parameter value. + required: false + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_appctrl: + name: "Ansible_Application_Control_Profile" + comment: "Created by Ansible Module TEST" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_appctrl: + name: "Ansible_Application_Control_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + entries: [{ + action: "block", + log: "enable", + log-packet: "enable", + protocols: ["1"], + quarantine: "attacker", + quarantine-log: "enable", + }, + {action: "pass", + category: ["2","3","4"]}, + ] +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + +############### +# START METHODS +############### + + +def fmgr_application_list_modify(fmgr, paramgram): + """ + fmgr_application_list -- Modifies Application Control Profiles on FortiManager + + :param fmgr: The fmgr object instance from fmgr_utils.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + + :return: The response from the FortiManager + :rtype: dict + """ + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if paramgram["mode"] in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/application/list'.format(adom=paramgram["adom"]) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif paramgram["mode"] == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/application/list/{name}'.format(adom=paramgram["adom"], + name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + unknown_application_log=dict(required=False, type="str", choices=["disable", "enable"]), + unknown_application_action=dict(required=False, type="str", choices=["pass", "block"]), + replacemsg_group=dict(required=False, type="str"), + p2p_black_list=dict(required=False, type="str", choices=["skype", "edonkey", "bittorrent"]), + other_application_log=dict(required=False, type="str", choices=["disable", "enable"]), + other_application_action=dict(required=False, type="str", choices=["pass", "block"]), + options=dict(required=False, type="str", + choices=["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]), + name=dict(required=False, type="str"), + extended_log=dict(required=False, type="str", choices=["disable", "enable"]), + deep_app_inspection=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + app_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]), + entries=dict(required=False, type="list"), + entries_action=dict(required=False, type="str", choices=["pass", "block", "reset"]), + entries_application=dict(required=False, type="str"), + entries_behavior=dict(required=False, type="str"), + entries_category=dict(required=False, type="str"), + entries_log=dict(required=False, type="str", choices=["disable", "enable"]), + entries_log_packet=dict(required=False, type="str", choices=["disable", "enable"]), + entries_per_ip_shaper=dict(required=False, type="str"), + entries_popularity=dict(required=False, type="str", choices=["1", "2", "3", "4", "5"]), + entries_protocols=dict(required=False, type="str"), + entries_quarantine=dict(required=False, type="str", choices=["none", "attacker"]), + entries_quarantine_expiry=dict(required=False, type="str"), + entries_quarantine_log=dict(required=False, type="str", choices=["disable", "enable"]), + entries_rate_count=dict(required=False, type="int"), + entries_rate_duration=dict(required=False, type="int"), + entries_rate_mode=dict(required=False, type="str", choices=["periodical", "continuous"]), + entries_rate_track=dict(required=False, type="str", + choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]), + entries_risk=dict(required=False, type="str"), + entries_session_ttl=dict(required=False, type="int"), + entries_shaper=dict(required=False, type="str"), + entries_shaper_reverse=dict(required=False, type="str"), + entries_sub_category=dict(required=False, type="str"), + entries_technology=dict(required=False, type="str"), + entries_vendor=dict(required=False, type="str"), + + entries_parameters_value=dict(required=False, type="str"), + + ) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "unknown-application-log": module.params["unknown_application_log"], + "unknown-application-action": module.params["unknown_application_action"], + "replacemsg-group": module.params["replacemsg_group"], + "p2p-black-list": module.params["p2p_black_list"], + "other-application-log": module.params["other_application_log"], + "other-application-action": module.params["other_application_action"], + "options": module.params["options"], + "name": module.params["name"], + "extended-log": module.params["extended_log"], + "deep-app-inspection": module.params["deep_app_inspection"], + "comment": module.params["comment"], + "app-replacemsg": module.params["app_replacemsg"], + "entries": { + "action": module.params["entries_action"], + "application": module.params["entries_application"], + "behavior": module.params["entries_behavior"], + "category": module.params["entries_category"], + "log": module.params["entries_log"], + "log-packet": module.params["entries_log_packet"], + "per-ip-shaper": module.params["entries_per_ip_shaper"], + "popularity": module.params["entries_popularity"], + "protocols": module.params["entries_protocols"], + "quarantine": module.params["entries_quarantine"], + "quarantine-expiry": module.params["entries_quarantine_expiry"], + "quarantine-log": module.params["entries_quarantine_log"], + "rate-count": module.params["entries_rate_count"], + "rate-duration": module.params["entries_rate_duration"], + "rate-mode": module.params["entries_rate_mode"], + "rate-track": module.params["entries_rate_track"], + "risk": module.params["entries_risk"], + "session-ttl": module.params["entries_session_ttl"], + "shaper": module.params["entries_shaper"], + "shaper-reverse": module.params["entries_shaper_reverse"], + "sub-category": module.params["entries_sub_category"], + "technology": module.params["entries_technology"], + "vendor": module.params["entries_vendor"], + "parameters": { + "value": module.params["entries_parameters_value"], + } + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['entries'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + try: + results = fmgr_application_list_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py new file mode 100644 index 000000000..88375cf16 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py @@ -0,0 +1,1386 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_av +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage security profile +description: + - Manage security profile groups for FortiManager objects + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + scan_mode: + description: + - Choose between full scan mode and quick scan mode. + required: false + choices: + - quick + - full + + replacemsg_group: + description: + - Replacement message group customized for this profile. + required: false + + name: + description: + - Profile name. + required: false + + mobile_malware_db: + description: + - Enable/disable using the mobile malware signature database. + required: false + choices: + - disable + - enable + + inspection_mode: + description: + - Inspection mode. + required: false + choices: + - proxy + - flow-based + + ftgd_analytics: + description: + - Settings to control which files are uploaded to FortiSandbox. + required: false + choices: + - disable + - suspicious + - everything + + extended_log: + description: + - Enable/disable extended logging for antivirus. + required: false + choices: + - disable + - enable + + comment: + description: + - Comment. + required: false + + av_virus_log: + description: + - Enable/disable AntiVirus logging. + required: false + choices: + - disable + - enable + + av_block_log: + description: + - Enable/disable logging for AntiVirus file blocking. + required: false + choices: + - disable + - enable + + analytics_wl_filetype: + description: + - Do not submit files matching this DLP file-pattern to FortiSandbox. + required: false + + analytics_max_upload: + description: + - Maximum size of files that can be uploaded to FortiSandbox (1 - 395 MBytes, default = 10). + required: false + + analytics_db: + description: + - Enable/disable using the FortiSandbox signature database to supplement the AV signature databases. + required: false + choices: + - disable + - enable + + analytics_bl_filetype: + description: + - Only submit files matching this DLP file-pattern to FortiSandbox. + required: false + + content_disarm: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + content_disarm_cover_page: + description: + - Enable/disable inserting a cover page into the disarmed document. + required: false + choices: + - disable + - enable + + content_disarm_detect_only: + description: + - Enable/disable only detect disarmable files, do not alter content. + required: false + choices: + - disable + - enable + + content_disarm_office_embed: + description: + - Enable/disable stripping of embedded objects in Microsoft Office documents. + required: false + choices: + - disable + - enable + + content_disarm_office_hylink: + description: + - Enable/disable stripping of hyperlinks in Microsoft Office documents. + required: false + choices: + - disable + - enable + + content_disarm_office_linked: + description: + - Enable/disable stripping of linked objects in Microsoft Office documents. + required: false + choices: + - disable + - enable + + content_disarm_office_macro: + description: + - Enable/disable stripping of macros in Microsoft Office documents. + required: false + choices: + - disable + - enable + + content_disarm_original_file_destination: + description: + - Destination to send original file if active content is removed. + required: false + choices: + - fortisandbox + - quarantine + - discard + + content_disarm_pdf_act_form: + description: + - Enable/disable stripping of actions that submit data to other targets in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_act_gotor: + description: + - Enable/disable stripping of links to other PDFs in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_act_java: + description: + - Enable/disable stripping of actions that execute JavaScript code in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_act_launch: + description: + - Enable/disable stripping of links to external applications in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_act_movie: + description: + - Enable/disable stripping of embedded movies in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_act_sound: + description: + - Enable/disable stripping of embedded sound files in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_embedfile: + description: + - Enable/disable stripping of embedded files in PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_hyperlink: + description: + - Enable/disable stripping of hyperlinks from PDF documents. + required: false + choices: + - disable + - enable + + content_disarm_pdf_javacode: + description: + - Enable/disable stripping of JavaScript code in PDF documents. + required: false + choices: + - disable + - enable + + ftp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ftp_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + ftp_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + ftp_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + ftp_options: + description: + - Enable/disable FTP AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + ftp_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + http: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + http_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + http_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + http_content_disarm: + description: + - Enable Content Disarm and Reconstruction for this protocol. + required: false + choices: + - disable + - enable + + http_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + http_options: + description: + - Enable/disable HTTP AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + http_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + imap: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + imap_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + imap_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + imap_content_disarm: + description: + - Enable Content Disarm and Reconstruction for this protocol. + required: false + choices: + - disable + - enable + + imap_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + imap_executables: + description: + - Treat Windows executable files as viruses for the purpose of blocking or monitoring. + required: false + choices: + - default + - virus + + imap_options: + description: + - Enable/disable IMAP AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + imap_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + mapi: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + mapi_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + mapi_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + mapi_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + mapi_executables: + description: + - Treat Windows executable files as viruses for the purpose of blocking or monitoring. + required: false + choices: + - default + - virus + + mapi_options: + description: + - Enable/disable MAPI AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + mapi_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + nac_quar: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + nac_quar_expiry: + description: + - Duration of quarantine. + required: false + + nac_quar_infected: + description: + - Enable/Disable quarantining infected hosts to the banned user list. + required: false + choices: + - none + - quar-src-ip + + nac_quar_log: + description: + - Enable/disable AntiVirus quarantine logging. + required: false + choices: + - disable + - enable + + nntp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + nntp_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + nntp_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + nntp_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + nntp_options: + description: + - Enable/disable NNTP AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + nntp_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + pop3: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + pop3_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + pop3_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + pop3_content_disarm: + description: + - Enable Content Disarm and Reconstruction for this protocol. + required: false + choices: + - disable + - enable + + pop3_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + pop3_executables: + description: + - Treat Windows executable files as viruses for the purpose of blocking or monitoring. + required: false + choices: + - default + - virus + + pop3_options: + description: + - Enable/disable POP3 AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + pop3_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + smb: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + smb_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + smb_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + smb_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + smb_options: + description: + - Enable/disable SMB AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + smb_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive + + smtp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + smtp_archive_block: + description: + - Select the archive types to block. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + smtp_archive_log: + description: + - Select the archive types to log. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - encrypted + - corrupted + - multipart + - nested + - mailbomb + - unhandled + - partiallycorrupted + - fileslimit + - timeout + + smtp_content_disarm: + description: + - Enable Content Disarm and Reconstruction for this protocol. + required: false + choices: + - disable + - enable + + smtp_emulator: + description: + - Enable/disable the virus emulator. + required: false + choices: + - disable + - enable + + smtp_executables: + description: + - Treat Windows executable files as viruses for the purpose of blocking or monitoring. + required: false + choices: + - default + - virus + + smtp_options: + description: + - Enable/disable SMTP AntiVirus scanning, monitoring, and quarantine. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - scan + - quarantine + - avmonitor + + smtp_outbreak_prevention: + description: + - Enable FortiGuard Virus Outbreak Prevention service. + required: false + choices: + - disabled + - files + - full-archive +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_av: + name: "Ansible_AV_Profile" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_av: + name: "Ansible_AV_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + inspection_mode: "proxy" + ftgd_analytics: "everything" + av_block_log: "enable" + av_virus_log: "enable" + scan_mode: "full" + mobile_malware_db: "enable" + ftp_archive_block: "encrypted" + ftp_outbreak_prevention: "files" + ftp_archive_log: "timeout" + ftp_emulator: "disable" + ftp_options: "scan" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + +############### +# START METHODS +############### + + +def fmgr_antivirus_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/antivirus/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + else: + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/antivirus/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + return response + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + scan_mode=dict(required=False, type="str", choices=["quick", "full"]), + replacemsg_group=dict(required=False, type="dict"), + name=dict(required=False, type="str"), + mobile_malware_db=dict(required=False, type="str", choices=["disable", "enable"]), + inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]), + ftgd_analytics=dict(required=False, type="str", choices=["disable", "suspicious", "everything"]), + extended_log=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + av_virus_log=dict(required=False, type="str", choices=["disable", "enable"]), + av_block_log=dict(required=False, type="str", choices=["disable", "enable"]), + analytics_wl_filetype=dict(required=False, type="dict"), + analytics_max_upload=dict(required=False, type="int"), + analytics_db=dict(required=False, type="str", choices=["disable", "enable"]), + analytics_bl_filetype=dict(required=False, type="dict"), + content_disarm=dict(required=False, type="list"), + content_disarm_cover_page=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_detect_only=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_office_embed=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_office_hylink=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_office_linked=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_office_macro=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_original_file_destination=dict(required=False, type="str", choices=["fortisandbox", + "quarantine", + "discard"]), + content_disarm_pdf_act_form=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_act_gotor=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_act_java=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_act_launch=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_act_movie=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_act_sound=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_embedfile=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_hyperlink=dict(required=False, type="str", choices=["disable", "enable"]), + content_disarm_pdf_javacode=dict(required=False, type="str", choices=["disable", "enable"]), + ftp=dict(required=False, type="list"), + ftp_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + ftp_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + ftp_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + ftp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + ftp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + http=dict(required=False, type="list"), + http_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + http_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + http_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]), + http_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + http_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + http_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + imap=dict(required=False, type="list"), + imap_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + imap_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + imap_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]), + imap_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + imap_executables=dict(required=False, type="str", choices=["default", "virus"]), + imap_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + imap_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + mapi=dict(required=False, type="list"), + mapi_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + mapi_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + mapi_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + mapi_executables=dict(required=False, type="str", choices=["default", "virus"]), + mapi_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + mapi_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + nac_quar=dict(required=False, type="list"), + nac_quar_expiry=dict(required=False, type="str"), + nac_quar_infected=dict(required=False, type="str", choices=["none", "quar-src-ip"]), + nac_quar_log=dict(required=False, type="str", choices=["disable", "enable"]), + nntp=dict(required=False, type="list"), + nntp_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + nntp_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + nntp_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + nntp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + nntp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + pop3=dict(required=False, type="list"), + pop3_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + pop3_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + pop3_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]), + pop3_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + pop3_executables=dict(required=False, type="str", choices=["default", "virus"]), + pop3_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + pop3_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + smb=dict(required=False, type="list"), + smb_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + smb_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + smb_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + smb_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + smb_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + smtp=dict(required=False, type="list"), + smtp_archive_block=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + smtp_archive_log=dict(required=False, type="str", choices=["encrypted", + "corrupted", + "multipart", + "nested", + "mailbomb", + "unhandled", + "partiallycorrupted", + "fileslimit", + "timeout"]), + smtp_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]), + smtp_emulator=dict(required=False, type="str", choices=["disable", "enable"]), + smtp_executables=dict(required=False, type="str", choices=["default", "virus"]), + smtp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]), + smtp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "scan-mode": module.params["scan_mode"], + "replacemsg-group": module.params["replacemsg_group"], + "name": module.params["name"], + "mobile-malware-db": module.params["mobile_malware_db"], + "inspection-mode": module.params["inspection_mode"], + "ftgd-analytics": module.params["ftgd_analytics"], + "extended-log": module.params["extended_log"], + "comment": module.params["comment"], + "av-virus-log": module.params["av_virus_log"], + "av-block-log": module.params["av_block_log"], + "analytics-wl-filetype": module.params["analytics_wl_filetype"], + "analytics-max-upload": module.params["analytics_max_upload"], + "analytics-db": module.params["analytics_db"], + "analytics-bl-filetype": module.params["analytics_bl_filetype"], + "content-disarm": { + "cover-page": module.params["content_disarm_cover_page"], + "detect-only": module.params["content_disarm_detect_only"], + "office-embed": module.params["content_disarm_office_embed"], + "office-hylink": module.params["content_disarm_office_hylink"], + "office-linked": module.params["content_disarm_office_linked"], + "office-macro": module.params["content_disarm_office_macro"], + "original-file-destination": module.params["content_disarm_original_file_destination"], + "pdf-act-form": module.params["content_disarm_pdf_act_form"], + "pdf-act-gotor": module.params["content_disarm_pdf_act_gotor"], + "pdf-act-java": module.params["content_disarm_pdf_act_java"], + "pdf-act-launch": module.params["content_disarm_pdf_act_launch"], + "pdf-act-movie": module.params["content_disarm_pdf_act_movie"], + "pdf-act-sound": module.params["content_disarm_pdf_act_sound"], + "pdf-embedfile": module.params["content_disarm_pdf_embedfile"], + "pdf-hyperlink": module.params["content_disarm_pdf_hyperlink"], + "pdf-javacode": module.params["content_disarm_pdf_javacode"], + }, + "ftp": { + "archive-block": module.params["ftp_archive_block"], + "archive-log": module.params["ftp_archive_log"], + "emulator": module.params["ftp_emulator"], + "options": module.params["ftp_options"], + "outbreak-prevention": module.params["ftp_outbreak_prevention"], + }, + "http": { + "archive-block": module.params["http_archive_block"], + "archive-log": module.params["http_archive_log"], + "content-disarm": module.params["http_content_disarm"], + "emulator": module.params["http_emulator"], + "options": module.params["http_options"], + "outbreak-prevention": module.params["http_outbreak_prevention"], + }, + "imap": { + "archive-block": module.params["imap_archive_block"], + "archive-log": module.params["imap_archive_log"], + "content-disarm": module.params["imap_content_disarm"], + "emulator": module.params["imap_emulator"], + "executables": module.params["imap_executables"], + "options": module.params["imap_options"], + "outbreak-prevention": module.params["imap_outbreak_prevention"], + }, + "mapi": { + "archive-block": module.params["mapi_archive_block"], + "archive-log": module.params["mapi_archive_log"], + "emulator": module.params["mapi_emulator"], + "executables": module.params["mapi_executables"], + "options": module.params["mapi_options"], + "outbreak-prevention": module.params["mapi_outbreak_prevention"], + }, + "nac-quar": { + "expiry": module.params["nac_quar_expiry"], + "infected": module.params["nac_quar_infected"], + "log": module.params["nac_quar_log"], + }, + "nntp": { + "archive-block": module.params["nntp_archive_block"], + "archive-log": module.params["nntp_archive_log"], + "emulator": module.params["nntp_emulator"], + "options": module.params["nntp_options"], + "outbreak-prevention": module.params["nntp_outbreak_prevention"], + }, + "pop3": { + "archive-block": module.params["pop3_archive_block"], + "archive-log": module.params["pop3_archive_log"], + "content-disarm": module.params["pop3_content_disarm"], + "emulator": module.params["pop3_emulator"], + "executables": module.params["pop3_executables"], + "options": module.params["pop3_options"], + "outbreak-prevention": module.params["pop3_outbreak_prevention"], + }, + "smb": { + "archive-block": module.params["smb_archive_block"], + "archive-log": module.params["smb_archive_log"], + "emulator": module.params["smb_emulator"], + "options": module.params["smb_options"], + "outbreak-prevention": module.params["smb_outbreak_prevention"], + }, + "smtp": { + "archive-block": module.params["smtp_archive_block"], + "archive-log": module.params["smtp_archive_log"], + "content-disarm": module.params["smtp_content_disarm"], + "emulator": module.params["smtp_emulator"], + "executables": module.params["smtp_executables"], + "options": module.params["smtp_options"], + "outbreak-prevention": module.params["smtp_outbreak_prevention"], + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ["content-disarm", "ftp", "http", "imap", "mapi", "nac-quar", "nntp", "pop3", "smb", "smtp"] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + module.paramgram = paramgram + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_antivirus_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py new file mode 100644 index 000000000..e6157ff4b --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py @@ -0,0 +1,339 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_dns +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage DNS security profiles in FortiManager +description: + - Manage DNS security profiles in FortiManager + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values. + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + youtube_restrict: + type: str + description: + - Set safe search for YouTube restriction level. + - choice | strict | Enable strict safe seach for YouTube. + - choice | moderate | Enable moderate safe search for YouTube. + required: false + choices: ["strict", "moderate"] + + sdns_ftgd_err_log: + type: str + description: + - Enable/disable FortiGuard SDNS rating error logging. + - choice | disable | Disable FortiGuard SDNS rating error logging. + - choice | enable | Enable FortiGuard SDNS rating error logging. + required: false + choices: ["disable", "enable"] + + sdns_domain_log: + type: str + description: + - Enable/disable domain filtering and botnet domain logging. + - choice | disable | Disable domain filtering and botnet domain logging. + - choice | enable | Enable domain filtering and botnet domain logging. + required: false + choices: ["disable", "enable"] + + safe_search: + type: str + description: + - Enable/disable Google, Bing, and YouTube safe search. + - choice | disable | Disable Google, Bing, and YouTube safe search. + - choice | enable | Enable Google, Bing, and YouTube safe search. + required: false + choices: ["disable", "enable"] + + redirect_portal: + type: str + description: + - IP address of the SDNS redirect portal. + required: false + + name: + type: str + description: + - Profile name. + required: false + + log_all_domain: + type: str + description: + - Enable/disable logging of all domains visited (detailed DNS logging). + - choice | disable | Disable logging of all domains visited. + - choice | enable | Enable logging of all domains visited. + required: false + choices: ["disable", "enable"] + + external_ip_blocklist: + type: str + description: + - One or more external IP block lists. + required: false + + comment: + type: str + description: + - Comment for the security profile to show in the FortiManager GUI. + required: false + + block_botnet: + type: str + description: + - Enable/disable blocking botnet C&C; DNS lookups. + - choice | disable | Disable blocking botnet C&C; DNS lookups. + - choice | enable | Enable blocking botnet C&C; DNS lookups. + required: false + choices: ["disable", "enable"] + + block_action: + type: str + description: + - Action to take for blocked domains. + - choice | block | Return NXDOMAIN for blocked domains. + - choice | redirect | Redirect blocked domains to SDNS portal. + required: false + choices: ["block", "redirect"] + + domain_filter_domain_filter_table: + type: str + description: + - DNS domain filter table ID. + required: false + + ftgd_dns_options: + type: str + description: + - FortiGuard DNS filter options. + - FLAG Based Options. Specify multiple in list form. + - flag | error-allow | Allow all domains when FortiGuard DNS servers fail. + - flag | ftgd-disable | Disable FortiGuard DNS domain rating. + required: false + choices: ["error-allow", "ftgd-disable"] + + ftgd_dns_filters_action: + type: str + description: + - Action to take for DNS requests matching the category. + - choice | monitor | Allow DNS requests matching the category and log the result. + - choice | block | Block DNS requests matching the category. + required: false + choices: ["monitor", "block"] + + ftgd_dns_filters_category: + type: str + description: + - Category number. + required: false + + ftgd_dns_filters_log: + type: str + description: + - Enable/disable DNS filter logging for this DNS profile. + - choice | disable | Disable DNS filter logging. + - choice | enable | Enable DNS filter logging. + required: false + choices: ["disable", "enable"] + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_dns: + name: "Ansible_DNS_Profile" + comment: "Created by Ansible Module TEST" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_dns: + name: "Ansible_DNS_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + block_action: "block" + + +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_dnsfilter_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + url = "" + datagram = {} + + response = DEFAULT_RESULT_OBJ + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/dnsfilter/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/dnsfilter/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + youtube_restrict=dict(required=False, type="str", choices=["strict", "moderate"]), + sdns_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]), + sdns_domain_log=dict(required=False, type="str", choices=["disable", "enable"]), + safe_search=dict(required=False, type="str", choices=["disable", "enable"]), + redirect_portal=dict(required=False, type="str"), + name=dict(required=False, type="str"), + log_all_domain=dict(required=False, type="str", choices=["disable", "enable"]), + external_ip_blocklist=dict(required=False, type="str"), + comment=dict(required=False, type="str"), + block_botnet=dict(required=False, type="str", choices=["disable", "enable"]), + block_action=dict(required=False, type="str", choices=["block", "redirect"]), + + domain_filter_domain_filter_table=dict(required=False, type="str"), + + ftgd_dns_options=dict(required=False, type="str", choices=["error-allow", "ftgd-disable"]), + + ftgd_dns_filters_action=dict(required=False, type="str", choices=["monitor", "block"]), + ftgd_dns_filters_category=dict(required=False, type="str"), + ftgd_dns_filters_log=dict(required=False, type="str", choices=["disable", "enable"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "youtube-restrict": module.params["youtube_restrict"], + "sdns-ftgd-err-log": module.params["sdns_ftgd_err_log"], + "sdns-domain-log": module.params["sdns_domain_log"], + "safe-search": module.params["safe_search"], + "redirect-portal": module.params["redirect_portal"], + "name": module.params["name"], + "log-all-domain": module.params["log_all_domain"], + "external-ip-blocklist": module.params["external_ip_blocklist"], + "comment": module.params["comment"], + "block-botnet": module.params["block_botnet"], + "block-action": module.params["block_action"], + "domain-filter": { + "domain-filter-table": module.params["domain_filter_domain_filter_table"], + }, + "ftgd-dns": { + "options": module.params["ftgd_dns_options"], + "filters": { + "action": module.params["ftgd_dns_filters_action"], + "category": module.params["ftgd_dns_filters_category"], + "log": module.params["ftgd_dns_filters_log"], + } + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_dnsfilter_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py new file mode 100644 index 000000000..4b5f8996c --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py @@ -0,0 +1,664 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_ips +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Managing IPS security profiles in FortiManager +description: + - Managing IPS security profiles in FortiManager + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + replacemsg_group: + description: + - Replacement message group. + required: false + + name: + description: + - Sensor name. + required: false + + extended_log: + description: + - Enable/disable extended logging. + required: false + choices: + - disable + - enable + + comment: + description: + - Comment. + required: false + + block_malicious_url: + description: + - Enable/disable malicious URL blocking. + required: false + choices: + - disable + - enable + + entries: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + entries_action: + description: + - Action taken with traffic in which signatures are detected. + required: false + choices: + - pass + - block + - reset + - default + + entries_application: + description: + - Applications to be protected. set application ? lists available applications. all includes + all applications. other includes all unlisted applications. + required: false + + entries_location: + description: + - Protect client or server traffic. + required: false + + entries_log: + description: + - Enable/disable logging of signatures included in filter. + required: false + choices: + - disable + - enable + + entries_log_attack_context: + description: + - Enable/disable logging of attack context| URL buffer, header buffer, body buffer, packet buffer. + required: false + choices: + - disable + - enable + + entries_log_packet: + description: + - Enable/disable packet logging. Enable to save the packet that triggers the filter. You can + download the packets in pcap format for diagnostic use. + required: false + choices: + - disable + - enable + + entries_os: + description: + - Operating systems to be protected. all includes all operating systems. other includes all + unlisted operating systems. + required: false + + entries_protocol: + description: + - Protocols to be examined. set protocol ? lists available protocols. all includes all protocols. + other includes all unlisted protocols. + required: false + + entries_quarantine: + description: + - Quarantine method. + required: false + choices: + - none + - attacker + + entries_quarantine_expiry: + description: + - Duration of quarantine. + required: false + + entries_quarantine_log: + description: + - Enable/disable quarantine logging. + required: false + choices: + - disable + - enable + + entries_rate_count: + description: + - Count of the rate. + required: false + + entries_rate_duration: + description: + - Duration (sec) of the rate. + required: false + + entries_rate_mode: + description: + - Rate limit mode. + required: false + choices: + - periodical + - continuous + + entries_rate_track: + description: + - Track the packet protocol field. + required: false + choices: + - none + - src-ip + - dest-ip + - dhcp-client-mac + - dns-domain + + entries_rule: + description: + - Identifies the predefined or custom IPS signatures to add to the sensor. + required: false + + entries_severity: + description: + - Relative severity of the signature, from info to critical. Log messages generated by the signature + include the severity. + required: false + + entries_status: + description: + - Status of the signatures included in filter. default enables the filter and only use filters + with default status of enable. Filters with default status of disable will not be used. + required: false + choices: + - disable + - enable + - default + + entries_exempt_ip_dst_ip: + description: + - Destination IP address and netmask. + required: false + + entries_exempt_ip_src_ip: + description: + - Source IP address and netmask. + required: false + + filter: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + filter_action: + description: + - Action of selected rules. + required: false + choices: + - pass + - block + - default + - reset + + filter_application: + description: + - Vulnerable application filter. + required: false + + filter_location: + description: + - Vulnerability location filter. + required: false + + filter_log: + description: + - Enable/disable logging of selected rules. + required: false + choices: + - disable + - enable + + filter_log_packet: + description: + - Enable/disable packet logging of selected rules. + required: false + choices: + - disable + - enable + + filter_name: + description: + - Filter name. + required: false + + filter_os: + description: + - Vulnerable OS filter. + required: false + + filter_protocol: + description: + - Vulnerable protocol filter. + required: false + + filter_quarantine: + description: + - Quarantine IP or interface. + required: false + choices: + - none + - attacker + + filter_quarantine_expiry: + description: + - Duration of quarantine in minute. + required: false + + filter_quarantine_log: + description: + - Enable/disable logging of selected quarantine. + required: false + choices: + - disable + - enable + + filter_severity: + description: + - Vulnerability severity filter. + required: false + + filter_status: + description: + - Selected rules status. + required: false + choices: + - disable + - enable + - default + + override: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + override_action: + description: + - Action of override rule. + required: false + choices: + - pass + - block + - reset + + override_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + override_log_packet: + description: + - Enable/disable packet logging. + required: false + choices: + - disable + - enable + + override_quarantine: + description: + - Quarantine IP or interface. + required: false + choices: + - none + - attacker + + override_quarantine_expiry: + description: + - Duration of quarantine in minute. + required: false + + override_quarantine_log: + description: + - Enable/disable logging of selected quarantine. + required: false + choices: + - disable + - enable + + override_rule_id: + description: + - Override rule ID. + required: false + + override_status: + description: + - Enable/disable status of override rule. + required: false + choices: + - disable + - enable + + override_exempt_ip_dst_ip: + description: + - Destination IP address and netmask. + required: false + + override_exempt_ip_src_ip: + description: + - Source IP address and netmask. + required: false +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_ips: + name: "Ansible_IPS_Profile" + comment: "Created by Ansible Module TEST" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_ips: + name: "Ansible_IPS_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + block_malicious_url: "enable" + entries: [{severity: "high", action: "block", log-packet: "enable"}, {severity: "medium", action: "pass"}] +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_ips_sensor_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/ips/sensor'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/ips/sensor/{name}'.format( + adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], + type="str", default="add"), + + replacemsg_group=dict(required=False, type="str"), + name=dict(required=False, type="str"), + extended_log=dict(required=False, type="str", + choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + block_malicious_url=dict(required=False, type="str", choices=[ + "disable", "enable"]), + entries=dict(required=False, type="list"), + entries_action=dict(required=False, type="str", choices=[ + "pass", "block", "reset", "default"]), + entries_application=dict(required=False, type="str"), + entries_location=dict(required=False, type="str"), + entries_log=dict(required=False, type="str", + choices=["disable", "enable"]), + entries_log_attack_context=dict( + required=False, type="str", choices=["disable", "enable"]), + entries_log_packet=dict(required=False, type="str", choices=[ + "disable", "enable"]), + entries_os=dict(required=False, type="str"), + entries_protocol=dict(required=False, type="str"), + entries_quarantine=dict(required=False, type="str", choices=[ + "none", "attacker"]), + entries_quarantine_expiry=dict(required=False, type="str"), + entries_quarantine_log=dict( + required=False, type="str", choices=["disable", "enable"]), + entries_rate_count=dict(required=False, type="int"), + entries_rate_duration=dict(required=False, type="int"), + entries_rate_mode=dict(required=False, type="str", choices=[ + "periodical", "continuous"]), + entries_rate_track=dict(required=False, type="str", + choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]), + entries_rule=dict(required=False, type="str"), + entries_severity=dict(required=False, type="str"), + entries_status=dict(required=False, type="str", choices=[ + "disable", "enable", "default"]), + + entries_exempt_ip_dst_ip=dict(required=False, type="str"), + entries_exempt_ip_src_ip=dict(required=False, type="str"), + filter=dict(required=False, type="list"), + filter_action=dict(required=False, type="str", choices=[ + "pass", "block", "default", "reset"]), + filter_application=dict(required=False, type="str"), + filter_location=dict(required=False, type="str"), + filter_log=dict(required=False, type="str", + choices=["disable", "enable"]), + filter_log_packet=dict(required=False, type="str", + choices=["disable", "enable"]), + filter_name=dict(required=False, type="str"), + filter_os=dict(required=False, type="str"), + filter_protocol=dict(required=False, type="str"), + filter_quarantine=dict(required=False, type="str", + choices=["none", "attacker"]), + filter_quarantine_expiry=dict(required=False, type="int"), + filter_quarantine_log=dict(required=False, type="str", choices=[ + "disable", "enable"]), + filter_severity=dict(required=False, type="str"), + filter_status=dict(required=False, type="str", choices=[ + "disable", "enable", "default"]), + override=dict(required=False, type="list"), + override_action=dict(required=False, type="str", + choices=["pass", "block", "reset"]), + override_log=dict(required=False, type="str", + choices=["disable", "enable"]), + override_log_packet=dict(required=False, type="str", choices=[ + "disable", "enable"]), + override_quarantine=dict(required=False, type="str", choices=[ + "none", "attacker"]), + override_quarantine_expiry=dict(required=False, type="int"), + override_quarantine_log=dict( + required=False, type="str", choices=["disable", "enable"]), + override_rule_id=dict(required=False, type="str"), + override_status=dict(required=False, type="str", + choices=["disable", "enable"]), + + override_exempt_ip_dst_ip=dict(required=False, type="str"), + override_exempt_ip_src_ip=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "replacemsg-group": module.params["replacemsg_group"], + "name": module.params["name"], + "extended-log": module.params["extended_log"], + "comment": module.params["comment"], + "block-malicious-url": module.params["block_malicious_url"], + "entries": { + "action": module.params["entries_action"], + "application": module.params["entries_application"], + "location": module.params["entries_location"], + "log": module.params["entries_log"], + "log-attack-context": module.params["entries_log_attack_context"], + "log-packet": module.params["entries_log_packet"], + "os": module.params["entries_os"], + "protocol": module.params["entries_protocol"], + "quarantine": module.params["entries_quarantine"], + "quarantine-expiry": module.params["entries_quarantine_expiry"], + "quarantine-log": module.params["entries_quarantine_log"], + "rate-count": module.params["entries_rate_count"], + "rate-duration": module.params["entries_rate_duration"], + "rate-mode": module.params["entries_rate_mode"], + "rate-track": module.params["entries_rate_track"], + "rule": module.params["entries_rule"], + "severity": module.params["entries_severity"], + "status": module.params["entries_status"], + "exempt-ip": { + "dst-ip": module.params["entries_exempt_ip_dst_ip"], + "src-ip": module.params["entries_exempt_ip_src_ip"], + }, + }, + "filter": { + "action": module.params["filter_action"], + "application": module.params["filter_application"], + "location": module.params["filter_location"], + "log": module.params["filter_log"], + "log-packet": module.params["filter_log_packet"], + "name": module.params["filter_name"], + "os": module.params["filter_os"], + "protocol": module.params["filter_protocol"], + "quarantine": module.params["filter_quarantine"], + "quarantine-expiry": module.params["filter_quarantine_expiry"], + "quarantine-log": module.params["filter_quarantine_log"], + "severity": module.params["filter_severity"], + "status": module.params["filter_status"], + }, + "override": { + "action": module.params["override_action"], + "log": module.params["override_log"], + "log-packet": module.params["override_log_packet"], + "quarantine": module.params["override_quarantine"], + "quarantine-expiry": module.params["override_quarantine_expiry"], + "quarantine-log": module.params["override_quarantine_log"], + "rule-id": module.params["override_rule_id"], + "status": module.params["override_status"], + "exempt-ip": { + "dst-ip": module.params["override_exempt_ip_dst_ip"], + "src-ip": module.params["override_exempt_ip_src_ip"], + } + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['entries', 'filter', 'override'] + + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + try: + results = fmgr_ips_sensor_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py new file mode 100644 index 000000000..4c65abf5b --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py @@ -0,0 +1,287 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_profile_group +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage security profiles within FortiManager +description: + - Manage security profile group which allows you to create a group of security profiles and apply that to a policy. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values. + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + webfilter_profile: + type: str + description: + - Name of an existing Web filter profile. + required: false + + waf_profile: + type: str + description: + - Name of an existing Web application firewall profile. + required: false + + voip_profile: + type: str + description: + - Name of an existing VoIP profile. + required: false + + ssl_ssh_profile: + type: str + description: + - Name of an existing SSL SSH profile. + required: false + + ssh_filter_profile: + type: str + description: + - Name of an existing SSH filter profile. + required: false + + spamfilter_profile: + type: str + description: + - Name of an existing Spam filter profile. + required: false + + profile_protocol_options: + type: str + description: + - Name of an existing Protocol options profile. + required: false + + name: + type: str + description: + - Profile group name. + required: false + + mms_profile: + type: str + description: + - Name of an existing MMS profile. + required: false + + ips_sensor: + type: str + description: + - Name of an existing IPS sensor. + required: false + + icap_profile: + type: str + description: + - Name of an existing ICAP profile. + required: false + + dnsfilter_profile: + type: str + description: + - Name of an existing DNS filter profile. + required: false + + dlp_sensor: + type: str + description: + - Name of an existing DLP sensor. + required: false + + av_profile: + type: str + description: + - Name of an existing Antivirus profile. + required: false + + application_list: + type: str + description: + - Name of an existing Application list. + required: false + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_profile_group: + name: "Ansible_TEST_Profile_Group" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_profile_group: + name: "Ansible_TEST_Profile_Group" + mode: "set" + av_profile: "Ansible_AV_Profile" + profile_protocol_options: "default" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_firewall_profile_group_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + url = "" + datagram = {} + + response = DEFAULT_RESULT_OBJ + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/firewall/profile-group'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/profile-group/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + webfilter_profile=dict(required=False, type="str"), + waf_profile=dict(required=False, type="str"), + voip_profile=dict(required=False, type="str"), + ssl_ssh_profile=dict(required=False, type="str"), + ssh_filter_profile=dict(required=False, type="str"), + spamfilter_profile=dict(required=False, type="str"), + profile_protocol_options=dict(required=False, type="str"), + name=dict(required=False, type="str"), + mms_profile=dict(required=False, type="str"), + ips_sensor=dict(required=False, type="str"), + icap_profile=dict(required=False, type="str"), + dnsfilter_profile=dict(required=False, type="str"), + dlp_sensor=dict(required=False, type="str"), + av_profile=dict(required=False, type="str"), + application_list=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "webfilter-profile": module.params["webfilter_profile"], + "waf-profile": module.params["waf_profile"], + "voip-profile": module.params["voip_profile"], + "ssl-ssh-profile": module.params["ssl_ssh_profile"], + "ssh-filter-profile": module.params["ssh_filter_profile"], + "spamfilter-profile": module.params["spamfilter_profile"], + "profile-protocol-options": module.params["profile_protocol_options"], + "name": module.params["name"], + "mms-profile": module.params["mms_profile"], + "ips-sensor": module.params["ips_sensor"], + "icap-profile": module.params["icap_profile"], + "dnsfilter-profile": module.params["dnsfilter_profile"], + "dlp-sensor": module.params["dlp_sensor"], + "av-profile": module.params["av_profile"], + "application-list": module.params["application_list"], + + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_firewall_profile_group_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py new file mode 100644 index 000000000..1b3ce8d13 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py @@ -0,0 +1,332 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_proxy +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage proxy security profiles in FortiManager +description: + - Manage proxy security profiles for FortiGates via FortiManager using the FMG API with playbooks + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + strip_encoding: + description: + - Enable/disable stripping unsupported encoding from the request header. + - choice | disable | Disable stripping of unsupported encoding from the request header. + - choice | enable | Enable stripping of unsupported encoding from the request header. + required: false + choices: ["disable", "enable"] + + name: + description: + - Profile name. + required: false + + log_header_change: + description: + - Enable/disable logging HTTP header changes. + - choice | disable | Disable Enable/disable logging HTTP header changes. + - choice | enable | Enable Enable/disable logging HTTP header changes. + required: false + choices: ["disable", "enable"] + + header_x_forwarded_for: + description: + - Action to take on the HTTP x-forwarded-for header in forwarded requests| forwards (pass), adds, or removes the + - HTTP header. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_x_authenticated_user: + description: + - Action to take on the HTTP x-authenticated-user header in forwarded requests| forwards (pass), adds, or remove + - s the HTTP header. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_x_authenticated_groups: + description: + - Action to take on the HTTP x-authenticated-groups header in forwarded requests| forwards (pass), adds, or remo + - ves the HTTP header. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_via_response: + description: + - Action to take on the HTTP via header in forwarded responses| forwards (pass), adds, or removes the HTTP heade + - r. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_via_request: + description: + - Action to take on the HTTP via header in forwarded requests| forwards (pass), adds, or removes the HTTP header + - . + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_front_end_https: + description: + - Action to take on the HTTP front-end-HTTPS header in forwarded requests| forwards (pass), adds, or removes the + - HTTP header. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + header_client_ip: + description: + - Actions to take on the HTTP client-IP header in forwarded requests| forwards (pass), adds, or removes the HTTP + - header. + - choice | pass | Forward the same HTTP header. + - choice | add | Add the HTTP header. + - choice | remove | Remove the HTTP header. + required: false + choices: ["pass", "add", "remove"] + + headers: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + headers_action: + description: + - Action when HTTP the header forwarded. + - choice | add-to-request | Add the HTTP header to request. + - choice | add-to-response | Add the HTTP header to response. + - choice | remove-from-request | Remove the HTTP header from request. + - choice | remove-from-response | Remove the HTTP header from response. + required: false + choices: ["add-to-request", "add-to-response", "remove-from-request", "remove-from-response"] + + headers_content: + description: + - HTTP header's content. + required: false + + headers_name: + description: + - HTTP forwarded header name. + required: false + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_proxy: + name: "Ansible_Web_Proxy_Profile" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_proxy: + name: "Ansible_Web_Proxy_Profile" + mode: "set" + header_client_ip: "pass" + header_front_end_https: "add" + header_via_request: "remove" + header_via_response: "pass" + header_x_authenticated_groups: "add" + header_x_authenticated_user: "remove" + strip_encoding: "enable" + log_header_change: "enable" + header_x_forwarded_for: "pass" + headers_action: "add-to-request" + headers_content: "test" + headers_name: "test_header" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_web_proxy_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/web-proxy/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/web-proxy/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + strip_encoding=dict(required=False, type="str", choices=["disable", "enable"]), + name=dict(required=False, type="str"), + log_header_change=dict(required=False, type="str", choices=["disable", "enable"]), + header_x_forwarded_for=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_x_authenticated_user=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_x_authenticated_groups=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_via_response=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_via_request=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_front_end_https=dict(required=False, type="str", choices=["pass", "add", "remove"]), + header_client_ip=dict(required=False, type="str", choices=["pass", "add", "remove"]), + headers=dict(required=False, type="list"), + headers_action=dict(required=False, type="str", choices=["add-to-request", "add-to-response", + "remove-from-request", "remove-from-response"]), + headers_content=dict(required=False, type="str"), + headers_name=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "strip-encoding": module.params["strip_encoding"], + "name": module.params["name"], + "log-header-change": module.params["log_header_change"], + "header-x-forwarded-for": module.params["header_x_forwarded_for"], + "header-x-authenticated-user": module.params["header_x_authenticated_user"], + "header-x-authenticated-groups": module.params["header_x_authenticated_groups"], + "header-via-response": module.params["header_via_response"], + "header-via-request": module.params["header_via_request"], + "header-front-end-https": module.params["header_front_end_https"], + "header-client-ip": module.params["header_client_ip"], + "headers": { + "action": module.params["headers_action"], + "content": module.params["headers_content"], + "name": module.params["headers_name"], + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['headers'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + module.paramgram = paramgram + + results = DEFAULT_RESULT_OBJ + try: + results = fmgr_web_proxy_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py new file mode 100644 index 000000000..ac5e918a8 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py @@ -0,0 +1,607 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_spam +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: spam filter profile for FMG +description: + - Manage spam filter security profiles within FortiManager via API + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + spam_rbl_table: + description: + - Anti-spam DNSBL table ID. + required: false + + spam_mheader_table: + description: + - Anti-spam MIME header table ID. + required: false + + spam_log_fortiguard_response: + description: + - Enable/disable logging FortiGuard spam response. + required: false + choices: + - disable + - enable + + spam_log: + description: + - Enable/disable spam logging for email filtering. + required: false + choices: + - disable + - enable + + spam_iptrust_table: + description: + - Anti-spam IP trust table ID. + required: false + + spam_filtering: + description: + - Enable/disable spam filtering. + required: false + choices: + - disable + - enable + + spam_bword_threshold: + description: + - Spam banned word threshold. + required: false + + spam_bword_table: + description: + - Anti-spam banned word table ID. + required: false + + spam_bwl_table: + description: + - Anti-spam black/white list table ID. + required: false + + replacemsg_group: + description: + - Replacement message group. + required: false + + options: + description: + - None + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - bannedword + - spamfsip + - spamfssubmit + - spamfschksum + - spamfsurl + - spamhelodns + - spamraddrdns + - spamrbl + - spamhdrcheck + - spamfsphish + - spambwl + + name: + description: + - Profile name. + required: false + + flow_based: + description: + - Enable/disable flow-based spam filtering. + required: false + choices: + - disable + - enable + + external: + description: + - Enable/disable external Email inspection. + required: false + choices: + - disable + - enable + + comment: + description: + - Comment. + required: false + + gmail: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + gmail_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + imap: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + imap_action: + description: + - Action for spam email. + required: false + choices: + - pass + - tag + + imap_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + imap_tag_msg: + description: + - Subject text or header added to spam email. + required: false + + imap_tag_type: + description: + - Tag subject or header for spam email. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - subject + - header + - spaminfo + + mapi: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + mapi_action: + description: + - Action for spam email. + required: false + choices: + - pass + - discard + + mapi_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + msn_hotmail: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + msn_hotmail_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + pop3: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + pop3_action: + description: + - Action for spam email. + required: false + choices: + - pass + - tag + + pop3_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + pop3_tag_msg: + description: + - Subject text or header added to spam email. + required: false + + pop3_tag_type: + description: + - Tag subject or header for spam email. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - subject + - header + - spaminfo + + smtp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + smtp_action: + description: + - Action for spam email. + required: false + choices: + - pass + - tag + - discard + + smtp_hdrip: + description: + - Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters. + required: false + choices: + - disable + - enable + + smtp_local_override: + description: + - Enable/disable local filter to override SMTP remote check result. + required: false + choices: + - disable + - enable + + smtp_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + smtp_tag_msg: + description: + - Subject text or header added to spam email. + required: false + + smtp_tag_type: + description: + - Tag subject or header for spam email. + - FLAG Based Options. Specify multiple in list form. + required: false + choices: + - subject + - header + - spaminfo + + yahoo_mail: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + yahoo_mail_log: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_spam: + name: "Ansible_Spam_Filter_Profile" + mode: "delete" + + - name: Create FMGR_SPAMFILTER_PROFILE + community.fortios.fmgr_secprof_spam: + host: "{{ inventory_hostname }}" + username: "{{ username }}" + password: "{{ password }}" + mode: "set" + adom: "root" + spam_log_fortiguard_response: "enable" + spam_iptrust_table: + spam_filtering: "enable" + spam_bword_threshold: 10 + options: ["bannedword", "spamfsip", "spamfsurl", "spamrbl", "spamfsphish", "spambwl"] + name: "Ansible_Spam_Filter_Profile" + flow_based: "enable" + external: "enable" + comment: "Created by Ansible" + gmail_log: "enable" + spam_log: "enable" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + +############### +# START METHODS +############### + + +def fmgr_spamfilter_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/spamfilter/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/spamfilter/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + spam_rbl_table=dict(required=False, type="str"), + spam_mheader_table=dict(required=False, type="str"), + spam_log_fortiguard_response=dict(required=False, type="str", choices=["disable", "enable"]), + spam_log=dict(required=False, type="str", choices=["disable", "enable"]), + spam_iptrust_table=dict(required=False, type="str"), + spam_filtering=dict(required=False, type="str", choices=["disable", "enable"]), + spam_bword_threshold=dict(required=False, type="int"), + spam_bword_table=dict(required=False, type="str"), + spam_bwl_table=dict(required=False, type="str"), + replacemsg_group=dict(required=False, type="str"), + options=dict(required=False, type="list", choices=["bannedword", + "spamfsip", + "spamfssubmit", + "spamfschksum", + "spamfsurl", + "spamhelodns", + "spamraddrdns", + "spamrbl", + "spamhdrcheck", + "spamfsphish", + "spambwl"]), + name=dict(required=False, type="str"), + flow_based=dict(required=False, type="str", choices=["disable", "enable"]), + external=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + gmail=dict(required=False, type="dict"), + gmail_log=dict(required=False, type="str", choices=["disable", "enable"]), + imap=dict(required=False, type="dict"), + imap_action=dict(required=False, type="str", choices=["pass", "tag"]), + imap_log=dict(required=False, type="str", choices=["disable", "enable"]), + imap_tag_msg=dict(required=False, type="str"), + imap_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]), + mapi=dict(required=False, type="dict"), + mapi_action=dict(required=False, type="str", choices=["pass", "discard"]), + mapi_log=dict(required=False, type="str", choices=["disable", "enable"]), + msn_hotmail=dict(required=False, type="dict"), + msn_hotmail_log=dict(required=False, type="str", choices=["disable", "enable"]), + pop3=dict(required=False, type="dict"), + pop3_action=dict(required=False, type="str", choices=["pass", "tag"]), + pop3_log=dict(required=False, type="str", choices=["disable", "enable"]), + pop3_tag_msg=dict(required=False, type="str"), + pop3_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]), + smtp=dict(required=False, type="dict"), + smtp_action=dict(required=False, type="str", choices=["pass", "tag", "discard"]), + smtp_hdrip=dict(required=False, type="str", choices=["disable", "enable"]), + smtp_local_override=dict(required=False, type="str", choices=["disable", "enable"]), + smtp_log=dict(required=False, type="str", choices=["disable", "enable"]), + smtp_tag_msg=dict(required=False, type="str"), + smtp_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]), + yahoo_mail=dict(required=False, type="dict"), + yahoo_mail_log=dict(required=False, type="str", choices=["disable", "enable"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "spam-rbl-table": module.params["spam_rbl_table"], + "spam-mheader-table": module.params["spam_mheader_table"], + "spam-log-fortiguard-response": module.params["spam_log_fortiguard_response"], + "spam-log": module.params["spam_log"], + "spam-iptrust-table": module.params["spam_iptrust_table"], + "spam-filtering": module.params["spam_filtering"], + "spam-bword-threshold": module.params["spam_bword_threshold"], + "spam-bword-table": module.params["spam_bword_table"], + "spam-bwl-table": module.params["spam_bwl_table"], + "replacemsg-group": module.params["replacemsg_group"], + "options": module.params["options"], + "name": module.params["name"], + "flow-based": module.params["flow_based"], + "external": module.params["external"], + "comment": module.params["comment"], + "gmail": { + "log": module.params["gmail_log"], + }, + "imap": { + "action": module.params["imap_action"], + "log": module.params["imap_log"], + "tag-msg": module.params["imap_tag_msg"], + "tag-type": module.params["imap_tag_type"], + }, + "mapi": { + "action": module.params["mapi_action"], + "log": module.params["mapi_log"], + }, + "msn-hotmail": { + "log": module.params["msn_hotmail_log"], + }, + "pop3": { + "action": module.params["pop3_action"], + "log": module.params["pop3_log"], + "tag-msg": module.params["pop3_tag_msg"], + "tag-type": module.params["pop3_tag_type"], + }, + "smtp": { + "action": module.params["smtp_action"], + "hdrip": module.params["smtp_hdrip"], + "local-override": module.params["smtp_local_override"], + "log": module.params["smtp_log"], + "tag-msg": module.params["smtp_tag_msg"], + "tag-type": module.params["smtp_tag_type"], + }, + "yahoo-mail": { + "log": module.params["yahoo_mail_log"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['gmail', 'imap', 'mapi', 'msn-hotmail', 'pop3', 'smtp', 'yahoo-mail'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + try: + + results = fmgr_spamfilter_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py new file mode 100644 index 000000000..1e9a0f7d7 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py @@ -0,0 +1,954 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_ssl_ssh +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage SSL and SSH security profiles in FortiManager +description: + - Manage SSL and SSH security profiles in FortiManager via the FMG API + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + whitelist: + description: + - Enable/disable exempting servers by FortiGuard whitelist. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + use_ssl_server: + description: + - Enable/disable the use of SSL server table for SSL offloading. + - choice | disable | Don't use SSL server configuration. + - choice | enable | Use SSL server configuration. + required: false + choices: ["disable", "enable"] + + untrusted_caname: + description: + - Untrusted CA certificate used by SSL Inspection. + required: false + + ssl_exemptions_log: + description: + - Enable/disable logging SSL exemptions. + - choice | disable | Disable logging SSL exemptions. + - choice | enable | Enable logging SSL exemptions. + required: false + choices: ["disable", "enable"] + + ssl_anomalies_log: + description: + - Enable/disable logging SSL anomalies. + - choice | disable | Disable logging SSL anomalies. + - choice | enable | Enable logging SSL anomalies. + required: false + choices: ["disable", "enable"] + + server_cert_mode: + description: + - Re-sign or replace the server's certificate. + - choice | re-sign | Multiple clients connecting to multiple servers. + - choice | replace | Protect an SSL server. + required: false + choices: ["re-sign", "replace"] + + server_cert: + description: + - Certificate used by SSL Inspection to replace server certificate. + required: false + + rpc_over_https: + description: + - Enable/disable inspection of RPC over HTTPS. + - choice | disable | Disable inspection of RPC over HTTPS. + - choice | enable | Enable inspection of RPC over HTTPS. + required: false + choices: ["disable", "enable"] + + name: + description: + - Name. + required: false + + mapi_over_https: + description: + - Enable/disable inspection of MAPI over HTTPS. + - choice | disable | Disable inspection of MAPI over HTTPS. + - choice | enable | Enable inspection of MAPI over HTTPS. + required: false + choices: ["disable", "enable"] + + comment: + description: + - Optional comments. + required: false + + caname: + description: + - CA certificate used by SSL Inspection. + required: false + + ftps: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ftps_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ftps_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ftps_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + ftps_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + ftps_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ftps_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + https: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + https_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + https_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + https_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + https_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | certificate-inspection | Inspect SSL handshake only. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "certificate-inspection", "deep-inspection"] + + https_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + https_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + imaps: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + imaps_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + imaps_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + imaps_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + imaps_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + imaps_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + imaps_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + pop3s: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + pop3s_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + pop3s_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + pop3s_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + pop3s_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + pop3s_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + pop3s_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + smtps: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + smtps_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + smtps_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + smtps_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + smtps_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + smtps_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + smtps_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + ssh: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssh_inspect_all: + description: + - Level of SSL inspection. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + ssh_ports: + description: + - Ports to use for scanning (1 - 65535, default = 443). + required: false + + ssh_ssh_algorithm: + description: + - Relative strength of encryption algorithms accepted during negotiation. + - choice | compatible | Allow a broader set of encryption algorithms for best compatibility. + - choice | high-encryption | Allow only AES-CTR, AES-GCM ciphers and high encryption algorithms. + required: false + choices: ["compatible", "high-encryption"] + + ssh_ssh_policy_check: + description: + - Enable/disable SSH policy check. + - choice | disable | Disable SSH policy check. + - choice | enable | Enable SSH policy check. + required: false + choices: ["disable", "enable"] + + ssh_ssh_tun_policy_check: + description: + - Enable/disable SSH tunnel policy check. + - choice | disable | Disable SSH tunnel policy check. + - choice | enable | Enable SSH tunnel policy check. + required: false + choices: ["disable", "enable"] + + ssh_status: + description: + - Configure protocol inspection status. + - choice | disable | Disable. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "deep-inspection"] + + ssh_unsupported_version: + description: + - Action based on SSH version being unsupported. + - choice | block | Block. + - choice | bypass | Bypass. + required: false + choices: ["block", "bypass"] + + ssl: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssl_allow_invalid_server_cert: + description: + - When enabled, allows SSL sessions whose server certificate validation failed. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ssl_client_cert_request: + description: + - Action based on client certificate request failure. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_inspect_all: + description: + - Level of SSL inspection. + - choice | disable | Disable. + - choice | certificate-inspection | Inspect SSL handshake only. + - choice | deep-inspection | Full SSL inspection. + required: false + choices: ["disable", "certificate-inspection", "deep-inspection"] + + ssl_unsupported_ssl: + description: + - Action based on the SSL encryption used being unsupported. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_untrusted_cert: + description: + - Allow, ignore, or block the untrusted SSL session server certificate. + - choice | allow | Allow the untrusted server certificate. + - choice | block | Block the connection when an untrusted server certificate is detected. + - choice | ignore | Always take the server certificate as trusted. + required: false + choices: ["allow", "block", "ignore"] + + ssl_exempt: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssl_exempt_address: + description: + - IPv4 address object. + required: false + + ssl_exempt_address6: + description: + - IPv6 address object. + required: false + + ssl_exempt_fortiguard_category: + description: + - FortiGuard category ID. + required: false + + ssl_exempt_regex: + description: + - Exempt servers by regular expression. + required: false + + ssl_exempt_type: + description: + - Type of address object (IPv4 or IPv6) or FortiGuard category. + - choice | fortiguard-category | FortiGuard category. + - choice | address | Firewall IPv4 address. + - choice | address6 | Firewall IPv6 address. + - choice | wildcard-fqdn | Fully Qualified Domain Name with wildcard characters. + - choice | regex | Regular expression FQDN. + required: false + choices: ["fortiguard-category", "address", "address6", "wildcard-fqdn", "regex"] + + ssl_exempt_wildcard_fqdn: + description: + - Exempt servers by wildcard FQDN. + required: false + + ssl_server: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ssl_server_ftps_client_cert_request: + description: + - Action based on client certificate request failure during the FTPS handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_server_https_client_cert_request: + description: + - Action based on client certificate request failure during the HTTPS handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_server_imaps_client_cert_request: + description: + - Action based on client certificate request failure during the IMAPS handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_server_ip: + description: + - IPv4 address of the SSL server. + required: false + + ssl_server_pop3s_client_cert_request: + description: + - Action based on client certificate request failure during the POP3S handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_server_smtps_client_cert_request: + description: + - Action based on client certificate request failure during the SMTPS handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + ssl_server_ssl_other_client_cert_request: + description: + - Action based on client certificate request failure during an SSL protocol handshake. + - choice | bypass | Bypass. + - choice | inspect | Inspect. + - choice | block | Block. + required: false + choices: ["bypass", "inspect", "block"] + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_ssl_ssh: + name: Ansible_SSL_SSH_Profile + mode: delete + + - name: CREATE Profile + community.fortios.fmgr_secprof_ssl_ssh: + name: Ansible_SSL_SSH_Profile + comment: "Created by Ansible Module TEST" + mode: set + mapi_over_https: enable + rpc_over_https: enable + server_cert_mode: replace + ssl_anomalies_log: enable + ssl_exemptions_log: enable + use_ssl_server: enable + whitelist: enable +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + +############### +# START METHODS +############### + + +def fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + whitelist=dict(required=False, type="str", choices=["disable", "enable"]), + use_ssl_server=dict(required=False, type="str", choices=["disable", "enable"]), + untrusted_caname=dict(required=False, type="str"), + ssl_exemptions_log=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_anomalies_log=dict(required=False, type="str", choices=["disable", "enable"]), + server_cert_mode=dict(required=False, type="str", choices=["re-sign", "replace"]), + server_cert=dict(required=False, type="str"), + rpc_over_https=dict(required=False, type="str", choices=["disable", "enable"]), + name=dict(required=False, type="str"), + mapi_over_https=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + caname=dict(required=False, type="str"), + ftps=dict(required=False, type="list"), + ftps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ftps_ports=dict(required=False, type="str"), + ftps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + ftps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ftps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + https=dict(required=False, type="list"), + https_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + https_ports=dict(required=False, type="str"), + https_status=dict(required=False, type="str", choices=["disable", "certificate-inspection", "deep-inspection"]), + https_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + https_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + imaps=dict(required=False, type="list"), + imaps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + imaps_ports=dict(required=False, type="str"), + imaps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + imaps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + imaps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + pop3s=dict(required=False, type="list"), + pop3s_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + pop3s_ports=dict(required=False, type="str"), + pop3s_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + pop3s_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + pop3s_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + smtps=dict(required=False, type="list"), + smtps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + smtps_ports=dict(required=False, type="str"), + smtps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + smtps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + smtps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + ssh=dict(required=False, type="list"), + ssh_inspect_all=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + ssh_ports=dict(required=False, type="str"), + ssh_ssh_algorithm=dict(required=False, type="str", choices=["compatible", "high-encryption"]), + ssh_ssh_policy_check=dict(required=False, type="str", choices=["disable", "enable"]), + ssh_ssh_tun_policy_check=dict(required=False, type="str", choices=["disable", "enable"]), + ssh_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]), + ssh_unsupported_version=dict(required=False, type="str", choices=["block", "bypass"]), + ssl=dict(required=False, type="list"), + ssl_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]), + ssl_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_inspect_all=dict(required=False, type="str", choices=["disable", "certificate-inspection", + "deep-inspection"]), + ssl_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]), + ssl_exempt=dict(required=False, type="list"), + ssl_exempt_address=dict(required=False, type="str"), + ssl_exempt_address6=dict(required=False, type="str"), + ssl_exempt_fortiguard_category=dict(required=False, type="str"), + ssl_exempt_regex=dict(required=False, type="str"), + ssl_exempt_type=dict(required=False, type="str", choices=["fortiguard-category", "address", "address6", + "wildcard-fqdn", "regex"]), + ssl_exempt_wildcard_fqdn=dict(required=False, type="str"), + ssl_server=dict(required=False, type="list"), + ssl_server_ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_server_https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_server_imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_server_ip=dict(required=False, type="str"), + ssl_server_pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_server_smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]), + ssl_server_ssl_other_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", + "block"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "whitelist": module.params["whitelist"], + "use-ssl-server": module.params["use_ssl_server"], + "untrusted-caname": module.params["untrusted_caname"], + "ssl-exemptions-log": module.params["ssl_exemptions_log"], + "ssl-anomalies-log": module.params["ssl_anomalies_log"], + "server-cert-mode": module.params["server_cert_mode"], + "server-cert": module.params["server_cert"], + "rpc-over-https": module.params["rpc_over_https"], + "name": module.params["name"], + "mapi-over-https": module.params["mapi_over_https"], + "comment": module.params["comment"], + "caname": module.params["caname"], + "ftps": { + "allow-invalid-server-cert": module.params["ftps_allow_invalid_server_cert"], + "client-cert-request": module.params["ftps_client_cert_request"], + "ports": module.params["ftps_ports"], + "status": module.params["ftps_status"], + "unsupported-ssl": module.params["ftps_unsupported_ssl"], + "untrusted-cert": module.params["ftps_untrusted_cert"], + }, + "https": { + "allow-invalid-server-cert": module.params["https_allow_invalid_server_cert"], + "client-cert-request": module.params["https_client_cert_request"], + "ports": module.params["https_ports"], + "status": module.params["https_status"], + "unsupported-ssl": module.params["https_unsupported_ssl"], + "untrusted-cert": module.params["https_untrusted_cert"], + }, + "imaps": { + "allow-invalid-server-cert": module.params["imaps_allow_invalid_server_cert"], + "client-cert-request": module.params["imaps_client_cert_request"], + "ports": module.params["imaps_ports"], + "status": module.params["imaps_status"], + "unsupported-ssl": module.params["imaps_unsupported_ssl"], + "untrusted-cert": module.params["imaps_untrusted_cert"], + }, + "pop3s": { + "allow-invalid-server-cert": module.params["pop3s_allow_invalid_server_cert"], + "client-cert-request": module.params["pop3s_client_cert_request"], + "ports": module.params["pop3s_ports"], + "status": module.params["pop3s_status"], + "unsupported-ssl": module.params["pop3s_unsupported_ssl"], + "untrusted-cert": module.params["pop3s_untrusted_cert"], + }, + "smtps": { + "allow-invalid-server-cert": module.params["smtps_allow_invalid_server_cert"], + "client-cert-request": module.params["smtps_client_cert_request"], + "ports": module.params["smtps_ports"], + "status": module.params["smtps_status"], + "unsupported-ssl": module.params["smtps_unsupported_ssl"], + "untrusted-cert": module.params["smtps_untrusted_cert"], + }, + "ssh": { + "inspect-all": module.params["ssh_inspect_all"], + "ports": module.params["ssh_ports"], + "ssh-algorithm": module.params["ssh_ssh_algorithm"], + "ssh-policy-check": module.params["ssh_ssh_policy_check"], + "ssh-tun-policy-check": module.params["ssh_ssh_tun_policy_check"], + "status": module.params["ssh_status"], + "unsupported-version": module.params["ssh_unsupported_version"], + }, + "ssl": { + "allow-invalid-server-cert": module.params["ssl_allow_invalid_server_cert"], + "client-cert-request": module.params["ssl_client_cert_request"], + "inspect-all": module.params["ssl_inspect_all"], + "unsupported-ssl": module.params["ssl_unsupported_ssl"], + "untrusted-cert": module.params["ssl_untrusted_cert"], + }, + "ssl-exempt": { + "address": module.params["ssl_exempt_address"], + "address6": module.params["ssl_exempt_address6"], + "fortiguard-category": module.params["ssl_exempt_fortiguard_category"], + "regex": module.params["ssl_exempt_regex"], + "type": module.params["ssl_exempt_type"], + "wildcard-fqdn": module.params["ssl_exempt_wildcard_fqdn"], + }, + "ssl-server": { + "ftps-client-cert-request": module.params["ssl_server_ftps_client_cert_request"], + "https-client-cert-request": module.params["ssl_server_https_client_cert_request"], + "imaps-client-cert-request": module.params["ssl_server_imaps_client_cert_request"], + "ip": module.params["ssl_server_ip"], + "pop3s-client-cert-request": module.params["ssl_server_pop3s_client_cert_request"], + "smtps-client-cert-request": module.params["ssl_server_smtps_client_cert_request"], + "ssl-other-client-cert-request": module.params["ssl_server_ssl_other_client_cert_request"], + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['ftps', 'https', 'imaps', 'pop3s', 'smtps', 'ssh', 'ssl', 'ssl-exempt', 'ssl-server'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + + try: + + results = fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py new file mode 100644 index 000000000..31b71288a --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py @@ -0,0 +1,1198 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_voip +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: VOIP security profiles in FMG +description: + - Manage VOIP security profiles in FortiManager via API + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + name: + description: + - Profile name. + required: false + + comment: + description: + - Comment. + required: false + + sccp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + sccp_block_mcast: + description: + - Enable/disable block multicast RTP connections. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sccp_log_call_summary: + description: + - Enable/disable log summary of SCCP calls. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sccp_log_violations: + description: + - Enable/disable logging of SCCP violations. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sccp_max_calls: + description: + - Maximum calls per minute per SCCP client (max 65535). + required: false + + sccp_status: + description: + - Enable/disable SCCP. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sccp_verify_header: + description: + - Enable/disable verify SCCP header content. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + sip_ack_rate: + description: + - ACK request rate limit (per second, per policy). + required: false + + sip_block_ack: + description: + - Enable/disable block ACK requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_bye: + description: + - Enable/disable block BYE requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_cancel: + description: + - Enable/disable block CANCEL requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_geo_red_options: + description: + - Enable/disable block OPTIONS requests, but OPTIONS requests still notify for redundancy. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_info: + description: + - Enable/disable block INFO requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_invite: + description: + - Enable/disable block INVITE requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_long_lines: + description: + - Enable/disable block requests with headers exceeding max-line-length. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_message: + description: + - Enable/disable block MESSAGE requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_notify: + description: + - Enable/disable block NOTIFY requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_options: + description: + - Enable/disable block OPTIONS requests and no OPTIONS as notifying message for redundancy either. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_prack: + description: + - Enable/disable block prack requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_publish: + description: + - Enable/disable block PUBLISH requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_refer: + description: + - Enable/disable block REFER requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_register: + description: + - Enable/disable block REGISTER requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_subscribe: + description: + - Enable/disable block SUBSCRIBE requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_unknown: + description: + - Block unrecognized SIP requests (enabled by default). + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_block_update: + description: + - Enable/disable block UPDATE requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_bye_rate: + description: + - BYE request rate limit (per second, per policy). + required: false + + sip_call_keepalive: + description: + - Continue tracking calls with no RTP for this many minutes. + required: false + + sip_cancel_rate: + description: + - CANCEL request rate limit (per second, per policy). + required: false + + sip_contact_fixup: + description: + - Fixup contact anyway even if contact's IP|port doesn't match session's IP|port. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_hnt_restrict_source_ip: + description: + - Enable/disable restrict RTP source IP to be the same as SIP source IP when HNT is enabled. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_hosted_nat_traversal: + description: + - Hosted NAT Traversal (HNT). + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_info_rate: + description: + - INFO request rate limit (per second, per policy). + required: false + + sip_invite_rate: + description: + - INVITE request rate limit (per second, per policy). + required: false + + sip_ips_rtp: + description: + - Enable/disable allow IPS on RTP. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_log_call_summary: + description: + - Enable/disable logging of SIP call summary. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_log_violations: + description: + - Enable/disable logging of SIP violations. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_malformed_header_allow: + description: + - Action for malformed Allow header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_call_id: + description: + - Action for malformed Call-ID header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_contact: + description: + - Action for malformed Contact header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_content_length: + description: + - Action for malformed Content-Length header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_content_type: + description: + - Action for malformed Content-Type header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_cseq: + description: + - Action for malformed CSeq header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_expires: + description: + - Action for malformed Expires header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_from: + description: + - Action for malformed From header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_max_forwards: + description: + - Action for malformed Max-Forwards header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_p_asserted_identity: + description: + - Action for malformed P-Asserted-Identity header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_rack: + description: + - Action for malformed RAck header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_record_route: + description: + - Action for malformed Record-Route header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_route: + description: + - Action for malformed Route header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_rseq: + description: + - Action for malformed RSeq header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_a: + description: + - Action for malformed SDP a line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_b: + description: + - Action for malformed SDP b line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_c: + description: + - Action for malformed SDP c line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_i: + description: + - Action for malformed SDP i line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_k: + description: + - Action for malformed SDP k line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_m: + description: + - Action for malformed SDP m line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_o: + description: + - Action for malformed SDP o line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_r: + description: + - Action for malformed SDP r line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_s: + description: + - Action for malformed SDP s line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_t: + description: + - Action for malformed SDP t line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_v: + description: + - Action for malformed SDP v line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_sdp_z: + description: + - Action for malformed SDP z line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_to: + description: + - Action for malformed To header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_header_via: + description: + - Action for malformed VIA header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_malformed_request_line: + description: + - Action for malformed request line. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_max_body_length: + description: + - Maximum SIP message body length (0 meaning no limit). + required: false + + sip_max_dialogs: + description: + - Maximum number of concurrent calls/dialogs (per policy). + required: false + + sip_max_idle_dialogs: + description: + - Maximum number established but idle dialogs to retain (per policy). + required: false + + sip_max_line_length: + description: + - Maximum SIP header line length (78-4096). + required: false + + sip_message_rate: + description: + - MESSAGE request rate limit (per second, per policy). + required: false + + sip_nat_trace: + description: + - Enable/disable preservation of original IP in SDP i line. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_no_sdp_fixup: + description: + - Enable/disable no SDP fix-up. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_notify_rate: + description: + - NOTIFY request rate limit (per second, per policy). + required: false + + sip_open_contact_pinhole: + description: + - Enable/disable open pinhole for non-REGISTER Contact port. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_open_record_route_pinhole: + description: + - Enable/disable open pinhole for Record-Route port. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_open_register_pinhole: + description: + - Enable/disable open pinhole for REGISTER Contact port. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_open_via_pinhole: + description: + - Enable/disable open pinhole for Via port. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_options_rate: + description: + - OPTIONS request rate limit (per second, per policy). + required: false + + sip_prack_rate: + description: + - PRACK request rate limit (per second, per policy). + required: false + + sip_preserve_override: + description: + - Override i line to preserve original IPS (default| append). + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_provisional_invite_expiry_time: + description: + - Expiry time for provisional INVITE (10 - 3600 sec). + required: false + + sip_publish_rate: + description: + - PUBLISH request rate limit (per second, per policy). + required: false + + sip_refer_rate: + description: + - REFER request rate limit (per second, per policy). + required: false + + sip_register_contact_trace: + description: + - Enable/disable trace original IP/port within the contact header of REGISTER requests. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_register_rate: + description: + - REGISTER request rate limit (per second, per policy). + required: false + + sip_rfc2543_branch: + description: + - Enable/disable support via branch compliant with RFC 2543. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_rtp: + description: + - Enable/disable create pinholes for RTP traffic to traverse firewall. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_ssl_algorithm: + description: + - Relative strength of encryption algorithms accepted in negotiation. + - choice | high | High encryption. Allow only AES and ChaCha. + - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4. + - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES. + required: false + choices: ["high", "medium", "low"] + + sip_ssl_auth_client: + description: + - Require a client certificate and authenticate it with the peer/peergrp. + required: false + + sip_ssl_auth_server: + description: + - Authenticate the server's certificate with the peer/peergrp. + required: false + + sip_ssl_client_certificate: + description: + - Name of Certificate to offer to server if requested. + required: false + + sip_ssl_client_renegotiation: + description: + - Allow/block client renegotiation by server. + - choice | allow | Allow a SSL client to renegotiate. + - choice | deny | Abort any SSL connection that attempts to renegotiate. + - choice | secure | Reject any SSL connection that does not offer a RFC 5746 Secure Renegotiation Indication. + required: false + choices: ["allow", "deny", "secure"] + + sip_ssl_max_version: + description: + - Highest SSL/TLS version to negotiate. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + sip_ssl_min_version: + description: + - Lowest SSL/TLS version to negotiate. + - choice | ssl-3.0 | SSL 3.0. + - choice | tls-1.0 | TLS 1.0. + - choice | tls-1.1 | TLS 1.1. + - choice | tls-1.2 | TLS 1.2. + required: false + choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"] + + sip_ssl_mode: + description: + - SSL/TLS mode for encryption & decryption of traffic. + - choice | off | No SSL. + - choice | full | Client to FortiGate and FortiGate to Server SSL. + required: false + choices: ["off", "full"] + + sip_ssl_pfs: + description: + - SSL Perfect Forward Secrecy. + - choice | require | PFS mandatory. + - choice | deny | PFS rejected. + - choice | allow | PFS allowed. + required: false + choices: ["require", "deny", "allow"] + + sip_ssl_send_empty_frags: + description: + - Send empty fragments to avoid attack on CBC IV (SSL 3.0 & TLS 1.0 only). + - choice | disable | Do not send empty fragments. + - choice | enable | Send empty fragments. + required: false + choices: ["disable", "enable"] + + sip_ssl_server_certificate: + description: + - Name of Certificate return to the client in every SSL connection. + required: false + + sip_status: + description: + - Enable/disable SIP. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_strict_register: + description: + - Enable/disable only allow the registrar to connect. + - choice | disable | Disable status. + - choice | enable | Enable status. + required: false + choices: ["disable", "enable"] + + sip_subscribe_rate: + description: + - SUBSCRIBE request rate limit (per second, per policy). + required: false + + sip_unknown_header: + description: + - Action for unknown SIP header. + - choice | pass | Bypass malformed messages. + - choice | discard | Discard malformed messages. + - choice | respond | Respond with error code. + required: false + choices: ["pass", "discard", "respond"] + + sip_update_rate: + description: + - UPDATE request rate limit (per second, per policy). + required: false + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_voip: + name: "Ansible_VOIP_Profile" + mode: "delete" + + - name: Create FMGR_VOIP_PROFILE + community.fortios.fmgr_secprof_voip: + mode: "set" + adom: "root" + name: "Ansible_VOIP_Profile" + comment: "Created by Ansible" + sccp: {block-mcast: "enable", log-call-summary: "enable", log-violations: "enable", status: "enable"} +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_voip_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/voip/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/voip/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + name=dict(required=False, type="str"), + comment=dict(required=False, type="str"), + sccp=dict(required=False, type="dict"), + sccp_block_mcast=dict(required=False, type="str", choices=["disable", "enable"]), + sccp_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]), + sccp_log_violations=dict(required=False, type="str", choices=["disable", "enable"]), + sccp_max_calls=dict(required=False, type="int"), + sccp_status=dict(required=False, type="str", choices=["disable", "enable"]), + sccp_verify_header=dict(required=False, type="str", choices=["disable", "enable"]), + sip=dict(required=False, type="dict"), + sip_ack_rate=dict(required=False, type="int"), + sip_block_ack=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_bye=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_cancel=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_geo_red_options=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_info=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_invite=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_long_lines=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_message=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_notify=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_options=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_prack=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_publish=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_refer=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_register=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_subscribe=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_unknown=dict(required=False, type="str", choices=["disable", "enable"]), + sip_block_update=dict(required=False, type="str", choices=["disable", "enable"]), + sip_bye_rate=dict(required=False, type="int"), + sip_call_keepalive=dict(required=False, type="int"), + sip_cancel_rate=dict(required=False, type="int"), + sip_contact_fixup=dict(required=False, type="str", choices=["disable", "enable"]), + sip_hnt_restrict_source_ip=dict(required=False, type="str", choices=["disable", "enable"]), + sip_hosted_nat_traversal=dict(required=False, type="str", choices=["disable", "enable"]), + sip_info_rate=dict(required=False, type="int"), + sip_invite_rate=dict(required=False, type="int"), + sip_ips_rtp=dict(required=False, type="str", choices=["disable", "enable"]), + sip_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]), + sip_log_violations=dict(required=False, type="str", choices=["disable", "enable"]), + sip_malformed_header_allow=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_call_id=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_contact=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_content_length=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_content_type=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_cseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_expires=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_from=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_max_forwards=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_p_asserted_identity=dict(required=False, type="str", choices=["pass", + "discard", + "respond"]), + sip_malformed_header_rack=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_record_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_rseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_a=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_b=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_c=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_i=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_k=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_m=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_o=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_r=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_s=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_t=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_v=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_sdp_z=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_to=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_header_via=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_malformed_request_line=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_max_body_length=dict(required=False, type="int"), + sip_max_dialogs=dict(required=False, type="int"), + sip_max_idle_dialogs=dict(required=False, type="int"), + sip_max_line_length=dict(required=False, type="int"), + sip_message_rate=dict(required=False, type="int"), + sip_nat_trace=dict(required=False, type="str", choices=["disable", "enable"]), + sip_no_sdp_fixup=dict(required=False, type="str", choices=["disable", "enable"]), + sip_notify_rate=dict(required=False, type="int"), + sip_open_contact_pinhole=dict(required=False, type="str", choices=["disable", "enable"]), + sip_open_record_route_pinhole=dict(required=False, type="str", choices=["disable", "enable"]), + sip_open_register_pinhole=dict(required=False, type="str", choices=["disable", "enable"]), + sip_open_via_pinhole=dict(required=False, type="str", choices=["disable", "enable"]), + sip_options_rate=dict(required=False, type="int"), + sip_prack_rate=dict(required=False, type="int"), + sip_preserve_override=dict(required=False, type="str", choices=["disable", "enable"]), + sip_provisional_invite_expiry_time=dict(required=False, type="int"), + sip_publish_rate=dict(required=False, type="int"), + sip_refer_rate=dict(required=False, type="int"), + sip_register_contact_trace=dict(required=False, type="str", choices=["disable", "enable"]), + sip_register_rate=dict(required=False, type="int"), + sip_rfc2543_branch=dict(required=False, type="str", choices=["disable", "enable"]), + sip_rtp=dict(required=False, type="str", choices=["disable", "enable"]), + sip_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low"]), + sip_ssl_auth_client=dict(required=False, type="str"), + sip_ssl_auth_server=dict(required=False, type="str"), + sip_ssl_client_certificate=dict(required=False, type="str"), + sip_ssl_client_renegotiation=dict(required=False, type="str", choices=["allow", "deny", "secure"]), + sip_ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + sip_ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]), + sip_ssl_mode=dict(required=False, type="str", choices=["off", "full"]), + sip_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]), + sip_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]), + sip_ssl_server_certificate=dict(required=False, type="str"), + sip_status=dict(required=False, type="str", choices=["disable", "enable"]), + sip_strict_register=dict(required=False, type="str", choices=["disable", "enable"]), + sip_subscribe_rate=dict(required=False, type="int"), + sip_unknown_header=dict(required=False, type="str", choices=["pass", "discard", "respond"]), + sip_update_rate=dict(required=False, type="int"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "name": module.params["name"], + "comment": module.params["comment"], + "sccp": { + "block-mcast": module.params["sccp_block_mcast"], + "log-call-summary": module.params["sccp_log_call_summary"], + "log-violations": module.params["sccp_log_violations"], + "max-calls": module.params["sccp_max_calls"], + "status": module.params["sccp_status"], + "verify-header": module.params["sccp_verify_header"], + }, + "sip": { + "ack-rate": module.params["sip_ack_rate"], + "block-ack": module.params["sip_block_ack"], + "block-bye": module.params["sip_block_bye"], + "block-cancel": module.params["sip_block_cancel"], + "block-geo-red-options": module.params["sip_block_geo_red_options"], + "block-info": module.params["sip_block_info"], + "block-invite": module.params["sip_block_invite"], + "block-long-lines": module.params["sip_block_long_lines"], + "block-message": module.params["sip_block_message"], + "block-notify": module.params["sip_block_notify"], + "block-options": module.params["sip_block_options"], + "block-prack": module.params["sip_block_prack"], + "block-publish": module.params["sip_block_publish"], + "block-refer": module.params["sip_block_refer"], + "block-register": module.params["sip_block_register"], + "block-subscribe": module.params["sip_block_subscribe"], + "block-unknown": module.params["sip_block_unknown"], + "block-update": module.params["sip_block_update"], + "bye-rate": module.params["sip_bye_rate"], + "call-keepalive": module.params["sip_call_keepalive"], + "cancel-rate": module.params["sip_cancel_rate"], + "contact-fixup": module.params["sip_contact_fixup"], + "hnt-restrict-source-ip": module.params["sip_hnt_restrict_source_ip"], + "hosted-nat-traversal": module.params["sip_hosted_nat_traversal"], + "info-rate": module.params["sip_info_rate"], + "invite-rate": module.params["sip_invite_rate"], + "ips-rtp": module.params["sip_ips_rtp"], + "log-call-summary": module.params["sip_log_call_summary"], + "log-violations": module.params["sip_log_violations"], + "malformed-header-allow": module.params["sip_malformed_header_allow"], + "malformed-header-call-id": module.params["sip_malformed_header_call_id"], + "malformed-header-contact": module.params["sip_malformed_header_contact"], + "malformed-header-content-length": module.params["sip_malformed_header_content_length"], + "malformed-header-content-type": module.params["sip_malformed_header_content_type"], + "malformed-header-cseq": module.params["sip_malformed_header_cseq"], + "malformed-header-expires": module.params["sip_malformed_header_expires"], + "malformed-header-from": module.params["sip_malformed_header_from"], + "malformed-header-max-forwards": module.params["sip_malformed_header_max_forwards"], + "malformed-header-p-asserted-identity": module.params["sip_malformed_header_p_asserted_identity"], + "malformed-header-rack": module.params["sip_malformed_header_rack"], + "malformed-header-record-route": module.params["sip_malformed_header_record_route"], + "malformed-header-route": module.params["sip_malformed_header_route"], + "malformed-header-rseq": module.params["sip_malformed_header_rseq"], + "malformed-header-sdp-a": module.params["sip_malformed_header_sdp_a"], + "malformed-header-sdp-b": module.params["sip_malformed_header_sdp_b"], + "malformed-header-sdp-c": module.params["sip_malformed_header_sdp_c"], + "malformed-header-sdp-i": module.params["sip_malformed_header_sdp_i"], + "malformed-header-sdp-k": module.params["sip_malformed_header_sdp_k"], + "malformed-header-sdp-m": module.params["sip_malformed_header_sdp_m"], + "malformed-header-sdp-o": module.params["sip_malformed_header_sdp_o"], + "malformed-header-sdp-r": module.params["sip_malformed_header_sdp_r"], + "malformed-header-sdp-s": module.params["sip_malformed_header_sdp_s"], + "malformed-header-sdp-t": module.params["sip_malformed_header_sdp_t"], + "malformed-header-sdp-v": module.params["sip_malformed_header_sdp_v"], + "malformed-header-sdp-z": module.params["sip_malformed_header_sdp_z"], + "malformed-header-to": module.params["sip_malformed_header_to"], + "malformed-header-via": module.params["sip_malformed_header_via"], + "malformed-request-line": module.params["sip_malformed_request_line"], + "max-body-length": module.params["sip_max_body_length"], + "max-dialogs": module.params["sip_max_dialogs"], + "max-idle-dialogs": module.params["sip_max_idle_dialogs"], + "max-line-length": module.params["sip_max_line_length"], + "message-rate": module.params["sip_message_rate"], + "nat-trace": module.params["sip_nat_trace"], + "no-sdp-fixup": module.params["sip_no_sdp_fixup"], + "notify-rate": module.params["sip_notify_rate"], + "open-contact-pinhole": module.params["sip_open_contact_pinhole"], + "open-record-route-pinhole": module.params["sip_open_record_route_pinhole"], + "open-register-pinhole": module.params["sip_open_register_pinhole"], + "open-via-pinhole": module.params["sip_open_via_pinhole"], + "options-rate": module.params["sip_options_rate"], + "prack-rate": module.params["sip_prack_rate"], + "preserve-override": module.params["sip_preserve_override"], + "provisional-invite-expiry-time": module.params["sip_provisional_invite_expiry_time"], + "publish-rate": module.params["sip_publish_rate"], + "refer-rate": module.params["sip_refer_rate"], + "register-contact-trace": module.params["sip_register_contact_trace"], + "register-rate": module.params["sip_register_rate"], + "rfc2543-branch": module.params["sip_rfc2543_branch"], + "rtp": module.params["sip_rtp"], + "ssl-algorithm": module.params["sip_ssl_algorithm"], + "ssl-auth-client": module.params["sip_ssl_auth_client"], + "ssl-auth-server": module.params["sip_ssl_auth_server"], + "ssl-client-certificate": module.params["sip_ssl_client_certificate"], + "ssl-client-renegotiation": module.params["sip_ssl_client_renegotiation"], + "ssl-max-version": module.params["sip_ssl_max_version"], + "ssl-min-version": module.params["sip_ssl_min_version"], + "ssl-mode": module.params["sip_ssl_mode"], + "ssl-pfs": module.params["sip_ssl_pfs"], + "ssl-send-empty-frags": module.params["sip_ssl_send_empty_frags"], + "ssl-server-certificate": module.params["sip_ssl_server_certificate"], + "status": module.params["sip_status"], + "strict-register": module.params["sip_strict_register"], + "subscribe-rate": module.params["sip_subscribe_rate"], + "unknown-header": module.params["sip_unknown_header"], + "update-rate": module.params["sip_update_rate"], + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['sccp', 'sip'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + module.paramgram = paramgram + + results = DEFAULT_RESULT_OBJ + try: + + results = fmgr_voip_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py new file mode 100644 index 000000000..6d7f40401 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py @@ -0,0 +1,1477 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of` +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_waf +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: FortiManager web application firewall security profile +description: + - Manage web application firewall security profiles for FGTs via FMG + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + name: + description: + - WAF Profile name. + required: false + + external: + description: + - Disable/Enable external HTTP Inspection. + - choice | disable | Disable external inspection. + - choice | enable | Enable external inspection. + required: false + choices: ["disable", "enable"] + + extended_log: + description: + - Enable/disable extended logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + comment: + description: + - Comment. + required: false + + address_list: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + address_list_blocked_address: + description: + - Blocked address. + required: false + + address_list_blocked_log: + description: + - Enable/disable logging on blocked addresses. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + address_list_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + address_list_status: + description: + - Status. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + address_list_trusted_address: + description: + - Trusted address. + required: false + + constraint: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + constraint_content_length_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_content_length_length: + description: + - Length of HTTP content in bytes (0 to 2147483647). + required: false + + constraint_content_length_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_content_length_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_content_length_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_address: + description: + - Host address. + required: false + + constraint_exception_content_length: + description: + - HTTP content length in request. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_header_length: + description: + - HTTP header length in request. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_hostname: + description: + - Enable/disable hostname check. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_line_length: + description: + - HTTP line length in request. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_malformed: + description: + - Enable/disable malformed HTTP request check. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_max_cookie: + description: + - Maximum number of cookies in HTTP request. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_max_header_line: + description: + - Maximum number of HTTP header line. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_max_range_segment: + description: + - Maximum number of range segments in HTTP range line. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_max_url_param: + description: + - Maximum number of parameters in URL. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_method: + description: + - Enable/disable HTTP method check. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_param_length: + description: + - Maximum length of parameter in URL, HTTP POST request or HTTP body. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_pattern: + description: + - URL pattern. + required: false + + constraint_exception_regex: + description: + - Enable/disable regular expression based pattern match. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_url_param_length: + description: + - Maximum length of parameter in URL. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_exception_version: + description: + - Enable/disable HTTP version check. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_header_length_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_header_length_length: + description: + - Length of HTTP header in bytes (0 to 2147483647). + required: false + + constraint_header_length_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_header_length_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_header_length_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_hostname_action: + description: + - Action for a hostname constraint. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_hostname_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_hostname_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_hostname_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_line_length_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_line_length_length: + description: + - Length of HTTP line in bytes (0 to 2147483647). + required: false + + constraint_line_length_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_line_length_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_line_length_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_malformed_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_malformed_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_malformed_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_malformed_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_cookie_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_max_cookie_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_cookie_max_cookie: + description: + - Maximum number of cookies in HTTP request (0 to 2147483647). + required: false + + constraint_max_cookie_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_max_cookie_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_header_line_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_max_header_line_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_header_line_max_header_line: + description: + - Maximum number HTTP header lines (0 to 2147483647). + required: false + + constraint_max_header_line_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_max_header_line_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_range_segment_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_max_range_segment_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_range_segment_max_range_segment: + description: + - Maximum number of range segments in HTTP range line (0 to 2147483647). + required: false + + constraint_max_range_segment_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_max_range_segment_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_url_param_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_max_url_param_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_max_url_param_max_url_param: + description: + - Maximum number of parameters in URL (0 to 2147483647). + required: false + + constraint_max_url_param_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_max_url_param_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_method_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_method_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_method_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_method_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_param_length_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_param_length_length: + description: + - Maximum length of parameter in URL, HTTP POST request or HTTP body in bytes (0 to 2147483647). + required: false + + constraint_param_length_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_param_length_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_param_length_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_url_param_length_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_url_param_length_length: + description: + - Maximum length of URL parameter in bytes (0 to 2147483647). + required: false + + constraint_url_param_length_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_url_param_length_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_url_param_length_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_version_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + required: false + choices: ["allow", "block"] + + constraint_version_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + constraint_version_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + constraint_version_status: + description: + - Enable/disable the constraint. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + method: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + method_default_allowed_methods: + description: + - Methods. + - FLAG Based Options. Specify multiple in list form. + - flag | delete | HTTP DELETE method. + - flag | get | HTTP GET method. + - flag | head | HTTP HEAD method. + - flag | options | HTTP OPTIONS method. + - flag | post | HTTP POST method. + - flag | put | HTTP PUT method. + - flag | trace | HTTP TRACE method. + - flag | others | Other HTTP methods. + - flag | connect | HTTP CONNECT method. + required: false + choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"] + + method_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + method_severity: + description: + - Severity. + - choice | low | low severity + - choice | medium | medium severity + - choice | high | High severity + required: false + choices: ["low", "medium", "high"] + + method_status: + description: + - Status. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + method_method_policy_address: + description: + - Host address. + required: false + + method_method_policy_allowed_methods: + description: + - Allowed Methods. + - FLAG Based Options. Specify multiple in list form. + - flag | delete | HTTP DELETE method. + - flag | get | HTTP GET method. + - flag | head | HTTP HEAD method. + - flag | options | HTTP OPTIONS method. + - flag | post | HTTP POST method. + - flag | put | HTTP PUT method. + - flag | trace | HTTP TRACE method. + - flag | others | Other HTTP methods. + - flag | connect | HTTP CONNECT method. + required: false + choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"] + + method_method_policy_pattern: + description: + - URL pattern. + required: false + + method_method_policy_regex: + description: + - Enable/disable regular expression based pattern match. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + signature: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + signature_credit_card_detection_threshold: + description: + - The minimum number of Credit cards to detect violation. + required: false + + signature_disabled_signature: + description: + - Disabled signatures + required: false + + signature_disabled_sub_class: + description: + - Disabled signature subclasses. + required: false + + signature_custom_signature_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + - choice | erase | Erase credit card numbers. + required: false + choices: ["allow", "block", "erase"] + + signature_custom_signature_case_sensitivity: + description: + - Case sensitivity in pattern. + - choice | disable | Case insensitive in pattern. + - choice | enable | Case sensitive in pattern. + required: false + choices: ["disable", "enable"] + + signature_custom_signature_direction: + description: + - Traffic direction. + - choice | request | Match HTTP request. + - choice | response | Match HTTP response. + required: false + choices: ["request", "response"] + + signature_custom_signature_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + signature_custom_signature_name: + description: + - Signature name. + required: false + + signature_custom_signature_pattern: + description: + - Match pattern. + required: false + + signature_custom_signature_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + signature_custom_signature_status: + description: + - Status. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + signature_custom_signature_target: + description: + - Match HTTP target. + - FLAG Based Options. Specify multiple in list form. + - flag | arg | HTTP arguments. + - flag | arg-name | Names of HTTP arguments. + - flag | req-body | HTTP request body. + - flag | req-cookie | HTTP request cookies. + - flag | req-cookie-name | HTTP request cookie names. + - flag | req-filename | HTTP request file name. + - flag | req-header | HTTP request headers. + - flag | req-header-name | HTTP request header names. + - flag | req-raw-uri | Raw URI of HTTP request. + - flag | req-uri | URI of HTTP request. + - flag | resp-body | HTTP response body. + - flag | resp-hdr | HTTP response headers. + - flag | resp-status | HTTP response status. + required: false + choices: ["arg","arg-name","req-body","req-cookie","req-cookie-name","req-filename","req-header","req-header-name", + "req-raw-uri","req-uri","resp-body","resp-hdr","resp-status"] + + signature_main_class_action: + description: + - Action. + - choice | allow | Allow. + - choice | block | Block. + - choice | erase | Erase credit card numbers. + required: false + choices: ["allow", "block", "erase"] + + signature_main_class_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + signature_main_class_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + signature_main_class_status: + description: + - Status. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + url_access: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + url_access_action: + description: + - Action. + - choice | bypass | Allow the HTTP request, also bypass further WAF scanning. + - choice | permit | Allow the HTTP request, and continue further WAF scanning. + - choice | block | Block HTTP request. + required: false + choices: ["bypass", "permit", "block"] + + url_access_address: + description: + - Host address. + required: false + + url_access_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + url_access_severity: + description: + - Severity. + - choice | low | Low severity. + - choice | medium | Medium severity. + - choice | high | High severity. + required: false + choices: ["low", "medium", "high"] + + url_access_access_pattern_negate: + description: + - Enable/disable match negation. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + url_access_access_pattern_pattern: + description: + - URL pattern. + required: false + + url_access_access_pattern_regex: + description: + - Enable/disable regular expression based pattern match. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + url_access_access_pattern_srcaddr: + description: + - Source address. + required: false + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_waf: + name: "Ansible_WAF_Profile" + comment: "Created by Ansible Module TEST" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_waf: + name: "Ansible_WAF_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_waf_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + mode = paramgram["mode"] + adom = paramgram["adom"] + # INIT A BASIC OBJECTS + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/waf/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/waf/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + name=dict(required=False, type="str"), + external=dict(required=False, type="str", choices=["disable", "enable"]), + extended_log=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + address_list=dict(required=False, type="list"), + address_list_blocked_address=dict(required=False, type="str"), + address_list_blocked_log=dict(required=False, type="str", choices=["disable", "enable"]), + address_list_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + address_list_status=dict(required=False, type="str", choices=["disable", "enable"]), + address_list_trusted_address=dict(required=False, type="str"), + constraint=dict(required=False, type="list"), + + constraint_content_length_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_content_length_length=dict(required=False, type="int"), + constraint_content_length_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_content_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_content_length_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_exception_address=dict(required=False, type="str"), + constraint_exception_content_length=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_header_length=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_hostname=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_line_length=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_malformed=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_max_cookie=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_max_header_line=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_max_range_segment=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_max_url_param=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_method=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_param_length=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_pattern=dict(required=False, type="str"), + constraint_exception_regex=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_url_param_length=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_exception_version=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_header_length_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_header_length_length=dict(required=False, type="int"), + constraint_header_length_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_header_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_header_length_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_hostname_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_hostname_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_hostname_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_hostname_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_line_length_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_line_length_length=dict(required=False, type="int"), + constraint_line_length_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_line_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_line_length_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_malformed_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_malformed_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_malformed_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_malformed_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_max_cookie_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_max_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_max_cookie_max_cookie=dict(required=False, type="int"), + constraint_max_cookie_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_max_cookie_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_max_header_line_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_max_header_line_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_max_header_line_max_header_line=dict(required=False, type="int"), + constraint_max_header_line_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_max_header_line_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_max_range_segment_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_max_range_segment_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_max_range_segment_max_range_segment=dict(required=False, type="int"), + constraint_max_range_segment_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_max_range_segment_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_max_url_param_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_max_url_param_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_max_url_param_max_url_param=dict(required=False, type="int"), + constraint_max_url_param_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_max_url_param_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_method_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_method_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_method_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_param_length_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_param_length_length=dict(required=False, type="int"), + constraint_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_url_param_length_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_url_param_length_length=dict(required=False, type="int"), + constraint_url_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_url_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_url_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]), + + constraint_version_action=dict(required=False, type="str", choices=["allow", "block"]), + constraint_version_log=dict(required=False, type="str", choices=["disable", "enable"]), + constraint_version_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + constraint_version_status=dict(required=False, type="str", choices=["disable", "enable"]), + method=dict(required=False, type="list"), + method_default_allowed_methods=dict(required=False, type="str", choices=["delete", + "get", + "head", + "options", + "post", + "put", + "trace", + "others", + "connect"]), + method_log=dict(required=False, type="str", choices=["disable", "enable"]), + method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + method_status=dict(required=False, type="str", choices=["disable", "enable"]), + + method_method_policy_address=dict(required=False, type="str"), + method_method_policy_allowed_methods=dict(required=False, type="str", choices=["delete", + "get", + "head", + "options", + "post", + "put", + "trace", + "others", + "connect"]), + method_method_policy_pattern=dict(required=False, type="str"), + method_method_policy_regex=dict(required=False, type="str", choices=["disable", "enable"]), + signature=dict(required=False, type="list"), + signature_credit_card_detection_threshold=dict(required=False, type="int"), + signature_disabled_signature=dict(required=False, type="str"), + signature_disabled_sub_class=dict(required=False, type="str"), + + signature_custom_signature_action=dict(required=False, type="str", choices=["allow", "block", "erase"]), + signature_custom_signature_case_sensitivity=dict(required=False, type="str", choices=["disable", "enable"]), + signature_custom_signature_direction=dict(required=False, type="str", choices=["request", "response"]), + signature_custom_signature_log=dict(required=False, type="str", choices=["disable", "enable"]), + signature_custom_signature_name=dict(required=False, type="str"), + signature_custom_signature_pattern=dict(required=False, type="str"), + signature_custom_signature_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + signature_custom_signature_status=dict(required=False, type="str", choices=["disable", "enable"]), + signature_custom_signature_target=dict(required=False, type="str", choices=["arg", + "arg-name", + "req-body", + "req-cookie", + "req-cookie-name", + "req-filename", + "req-header", + "req-header-name", + "req-raw-uri", + "req-uri", + "resp-body", + "resp-hdr", + "resp-status"]), + + signature_main_class_action=dict(required=False, type="str", choices=["allow", "block", "erase"]), + signature_main_class_log=dict(required=False, type="str", choices=["disable", "enable"]), + signature_main_class_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + signature_main_class_status=dict(required=False, type="str", choices=["disable", "enable"]), + url_access=dict(required=False, type="list"), + url_access_action=dict(required=False, type="str", choices=["bypass", "permit", "block"]), + url_access_address=dict(required=False, type="str"), + url_access_log=dict(required=False, type="str", choices=["disable", "enable"]), + url_access_severity=dict(required=False, type="str", choices=["low", "medium", "high"]), + + url_access_access_pattern_negate=dict(required=False, type="str", choices=["disable", "enable"]), + url_access_access_pattern_pattern=dict(required=False, type="str"), + url_access_access_pattern_regex=dict(required=False, type="str", choices=["disable", "enable"]), + url_access_access_pattern_srcaddr=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "name": module.params["name"], + "external": module.params["external"], + "extended-log": module.params["extended_log"], + "comment": module.params["comment"], + "address-list": { + "blocked-address": module.params["address_list_blocked_address"], + "blocked-log": module.params["address_list_blocked_log"], + "severity": module.params["address_list_severity"], + "status": module.params["address_list_status"], + "trusted-address": module.params["address_list_trusted_address"], + }, + "constraint": { + "content-length": { + "action": module.params["constraint_content_length_action"], + "length": module.params["constraint_content_length_length"], + "log": module.params["constraint_content_length_log"], + "severity": module.params["constraint_content_length_severity"], + "status": module.params["constraint_content_length_status"], + }, + "exception": { + "address": module.params["constraint_exception_address"], + "content-length": module.params["constraint_exception_content_length"], + "header-length": module.params["constraint_exception_header_length"], + "hostname": module.params["constraint_exception_hostname"], + "line-length": module.params["constraint_exception_line_length"], + "malformed": module.params["constraint_exception_malformed"], + "max-cookie": module.params["constraint_exception_max_cookie"], + "max-header-line": module.params["constraint_exception_max_header_line"], + "max-range-segment": module.params["constraint_exception_max_range_segment"], + "max-url-param": module.params["constraint_exception_max_url_param"], + "method": module.params["constraint_exception_method"], + "param-length": module.params["constraint_exception_param_length"], + "pattern": module.params["constraint_exception_pattern"], + "regex": module.params["constraint_exception_regex"], + "url-param-length": module.params["constraint_exception_url_param_length"], + "version": module.params["constraint_exception_version"], + }, + "header-length": { + "action": module.params["constraint_header_length_action"], + "length": module.params["constraint_header_length_length"], + "log": module.params["constraint_header_length_log"], + "severity": module.params["constraint_header_length_severity"], + "status": module.params["constraint_header_length_status"], + }, + "hostname": { + "action": module.params["constraint_hostname_action"], + "log": module.params["constraint_hostname_log"], + "severity": module.params["constraint_hostname_severity"], + "status": module.params["constraint_hostname_status"], + }, + "line-length": { + "action": module.params["constraint_line_length_action"], + "length": module.params["constraint_line_length_length"], + "log": module.params["constraint_line_length_log"], + "severity": module.params["constraint_line_length_severity"], + "status": module.params["constraint_line_length_status"], + }, + "malformed": { + "action": module.params["constraint_malformed_action"], + "log": module.params["constraint_malformed_log"], + "severity": module.params["constraint_malformed_severity"], + "status": module.params["constraint_malformed_status"], + }, + "max-cookie": { + "action": module.params["constraint_max_cookie_action"], + "log": module.params["constraint_max_cookie_log"], + "max-cookie": module.params["constraint_max_cookie_max_cookie"], + "severity": module.params["constraint_max_cookie_severity"], + "status": module.params["constraint_max_cookie_status"], + }, + "max-header-line": { + "action": module.params["constraint_max_header_line_action"], + "log": module.params["constraint_max_header_line_log"], + "max-header-line": module.params["constraint_max_header_line_max_header_line"], + "severity": module.params["constraint_max_header_line_severity"], + "status": module.params["constraint_max_header_line_status"], + }, + "max-range-segment": { + "action": module.params["constraint_max_range_segment_action"], + "log": module.params["constraint_max_range_segment_log"], + "max-range-segment": module.params["constraint_max_range_segment_max_range_segment"], + "severity": module.params["constraint_max_range_segment_severity"], + "status": module.params["constraint_max_range_segment_status"], + }, + "max-url-param": { + "action": module.params["constraint_max_url_param_action"], + "log": module.params["constraint_max_url_param_log"], + "max-url-param": module.params["constraint_max_url_param_max_url_param"], + "severity": module.params["constraint_max_url_param_severity"], + "status": module.params["constraint_max_url_param_status"], + }, + "method": { + "action": module.params["constraint_method_action"], + "log": module.params["constraint_method_log"], + "severity": module.params["constraint_method_severity"], + "status": module.params["constraint_method_status"], + }, + "param-length": { + "action": module.params["constraint_param_length_action"], + "length": module.params["constraint_param_length_length"], + "log": module.params["constraint_param_length_log"], + "severity": module.params["constraint_param_length_severity"], + "status": module.params["constraint_param_length_status"], + }, + "url-param-length": { + "action": module.params["constraint_url_param_length_action"], + "length": module.params["constraint_url_param_length_length"], + "log": module.params["constraint_url_param_length_log"], + "severity": module.params["constraint_url_param_length_severity"], + "status": module.params["constraint_url_param_length_status"], + }, + "version": { + "action": module.params["constraint_version_action"], + "log": module.params["constraint_version_log"], + "severity": module.params["constraint_version_severity"], + "status": module.params["constraint_version_status"], + }, + }, + "method": { + "default-allowed-methods": module.params["method_default_allowed_methods"], + "log": module.params["method_log"], + "severity": module.params["method_severity"], + "status": module.params["method_status"], + "method-policy": { + "address": module.params["method_method_policy_address"], + "allowed-methods": module.params["method_method_policy_allowed_methods"], + "pattern": module.params["method_method_policy_pattern"], + "regex": module.params["method_method_policy_regex"], + }, + }, + "signature": { + "credit-card-detection-threshold": module.params["signature_credit_card_detection_threshold"], + "disabled-signature": module.params["signature_disabled_signature"], + "disabled-sub-class": module.params["signature_disabled_sub_class"], + "custom-signature": { + "action": module.params["signature_custom_signature_action"], + "case-sensitivity": module.params["signature_custom_signature_case_sensitivity"], + "direction": module.params["signature_custom_signature_direction"], + "log": module.params["signature_custom_signature_log"], + "name": module.params["signature_custom_signature_name"], + "pattern": module.params["signature_custom_signature_pattern"], + "severity": module.params["signature_custom_signature_severity"], + "status": module.params["signature_custom_signature_status"], + "target": module.params["signature_custom_signature_target"], + }, + "main-class": { + "action": module.params["signature_main_class_action"], + "log": module.params["signature_main_class_log"], + "severity": module.params["signature_main_class_severity"], + "status": module.params["signature_main_class_status"], + }, + }, + "url-access": { + "action": module.params["url_access_action"], + "address": module.params["url_access_address"], + "log": module.params["url_access_log"], + "severity": module.params["url_access_severity"], + "access-pattern": { + "negate": module.params["url_access_access_pattern_negate"], + "pattern": module.params["url_access_access_pattern_pattern"], + "regex": module.params["url_access_access_pattern_regex"], + "srcaddr": module.params["url_access_access_pattern_srcaddr"], + } + } + } + + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['address-list', 'constraint', 'method', 'signature', 'url-access'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_waf_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py new file mode 100644 index 000000000..68f0962b7 --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py @@ -0,0 +1,685 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_wanopt +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: WAN optimization +description: + - Manage WanOpt security profiles in FortiManager via API + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + transparent: + description: + - Enable/disable transparent mode. + required: false + choices: + - disable + - enable + + name: + description: + - Profile name. + required: false + + comments: + description: + - Comment. + required: false + + auth_group: + description: + - Optionally add an authentication group to restrict access to the WAN Optimization tunnel to + peers in the authentication group. + required: false + + cifs: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + cifs_byte_caching: + description: + - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching + file data sent across the WAN and in future serving if from the cache. + required: false + choices: + - disable + - enable + + cifs_log_traffic: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + cifs_port: + description: + - Single port number or port number range for CIFS. Only packets with a destination port number + that matches this port number or range are accepted by this profile. + required: false + + cifs_prefer_chunking: + description: + - Select dynamic or fixed-size data chunking for HTTP WAN Optimization. + required: false + choices: + - dynamic + - fix + + cifs_secure_tunnel: + description: + - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the + same TCP port (7810). + required: false + choices: + - disable + - enable + + cifs_status: + description: + - Enable/disable HTTP WAN Optimization. + required: false + choices: + - disable + - enable + + cifs_tunnel_sharing: + description: + - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols. + required: false + choices: + - private + - shared + - express-shared + + ftp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ftp_byte_caching: + description: + - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching + file data sent across the WAN and in future serving if from the cache. + required: false + choices: + - disable + - enable + + ftp_log_traffic: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + ftp_port: + description: + - Single port number or port number range for FTP. Only packets with a destination port number + that matches this port number or range are accepted by this profile. + required: false + + ftp_prefer_chunking: + description: + - Select dynamic or fixed-size data chunking for HTTP WAN Optimization. + required: false + choices: + - dynamic + - fix + + ftp_secure_tunnel: + description: + - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the + same TCP port (7810). + required: false + choices: + - disable + - enable + + ftp_status: + description: + - Enable/disable HTTP WAN Optimization. + required: false + choices: + - disable + - enable + + ftp_tunnel_sharing: + description: + - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols. + required: false + choices: + - private + - shared + - express-shared + + http: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + http_byte_caching: + description: + - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching + file data sent across the WAN and in future serving if from the cache. + required: false + choices: + - disable + - enable + + http_log_traffic: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + http_port: + description: + - Single port number or port number range for HTTP. Only packets with a destination port number + that matches this port number or range are accepted by this profile. + required: false + + http_prefer_chunking: + description: + - Select dynamic or fixed-size data chunking for HTTP WAN Optimization. + required: false + choices: + - dynamic + - fix + + http_secure_tunnel: + description: + - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the + same TCP port (7810). + required: false + choices: + - disable + - enable + + http_ssl: + description: + - Enable/disable SSL/TLS offloading (hardware acceleration) for HTTPS traffic in this tunnel. + required: false + choices: + - disable + - enable + + http_ssl_port: + description: + - Port on which to expect HTTPS traffic for SSL/TLS offloading. + required: false + + http_status: + description: + - Enable/disable HTTP WAN Optimization. + required: false + choices: + - disable + - enable + + http_tunnel_non_http: + description: + - Configure how to process non-HTTP traffic when a profile configured for HTTP traffic accepts + a non-HTTP session. Can occur if an application sends non-HTTP traffic using an HTTP destination port. + required: false + choices: + - disable + - enable + + http_tunnel_sharing: + description: + - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols. + required: false + choices: + - private + - shared + - express-shared + + http_unknown_http_version: + description: + - How to handle HTTP sessions that do not comply with HTTP 0.9, 1.0, or 1.1. + required: false + choices: + - best-effort + - reject + - tunnel + + mapi: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + mapi_byte_caching: + description: + - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching + file data sent across the WAN and in future serving if from the cache. + required: false + choices: + - disable + - enable + + mapi_log_traffic: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + mapi_port: + description: + - Single port number or port number range for MAPI. Only packets with a destination port number + that matches this port number or range are accepted by this profile. + required: false + + mapi_secure_tunnel: + description: + - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the + same TCP port (7810). + required: false + choices: + - disable + - enable + + mapi_status: + description: + - Enable/disable HTTP WAN Optimization. + required: false + choices: + - disable + - enable + + mapi_tunnel_sharing: + description: + - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols. + required: false + choices: + - private + - shared + - express-shared + + tcp: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + tcp_byte_caching: + description: + - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching + file data sent across the WAN and in future serving if from the cache. + required: false + choices: + - disable + - enable + + tcp_byte_caching_opt: + description: + - Select whether TCP byte-caching uses system memory only or both memory and disk space. + required: false + choices: + - mem-only + - mem-disk + + tcp_log_traffic: + description: + - Enable/disable logging. + required: false + choices: + - disable + - enable + + tcp_port: + description: + - Single port number or port number range for TCP. Only packets with a destination port number + that matches this port number or range are accepted by this profile. + required: false + + tcp_secure_tunnel: + description: + - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the + same TCP port (7810). + required: false + choices: + - disable + - enable + + tcp_ssl: + description: + - Enable/disable SSL/TLS offloading. + required: false + choices: + - disable + - enable + + tcp_ssl_port: + description: + - Port on which to expect HTTPS traffic for SSL/TLS offloading. + required: false + + tcp_status: + description: + - Enable/disable HTTP WAN Optimization. + required: false + choices: + - disable + - enable + + tcp_tunnel_sharing: + description: + - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols. + required: false + choices: + - private + - shared + - express-shared + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_wanopt: + name: "Ansible_WanOpt_Profile" + mode: "delete" + + - name: Create FMGR_WANOPT_PROFILE + community.fortios.fmgr_secprof_wanopt: + mode: "set" + adom: "root" + transparent: "enable" + name: "Ansible_WanOpt_Profile" + comments: "Created by Ansible" + cifs: {byte-caching: "enable", + log-traffic: "enable", + port: 80, + prefer-chunking: "dynamic", + status: "enable", + tunnel-sharing: "private"} + ftp: {byte-caching: "enable", + log-traffic: "enable", + port: 80, + prefer-chunking: "dynamic", + secure-tunnel: "disable", + status: "enable", + tunnel-sharing: "private"} +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +############### +# START METHODS +############### + + +def fmgr_wanopt_profile_modify(fmgr, paramgram): + """ + :param fmgr: The fmgr object instance from fortimanager.py + :type fmgr: class object + :param paramgram: The formatted dictionary of options to process + :type paramgram: dict + :return: The response from the FortiManager + :rtype: dict + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/wanopt/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/wanopt/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + transparent=dict(required=False, type="str", choices=["disable", "enable"]), + name=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + auth_group=dict(required=False, type="str"), + cifs=dict(required=False, type="dict"), + cifs_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]), + cifs_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]), + cifs_port=dict(required=False, type="str"), + cifs_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]), + cifs_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]), + cifs_status=dict(required=False, type="str", choices=["disable", "enable"]), + cifs_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]), + ftp=dict(required=False, type="dict"), + ftp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]), + ftp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]), + ftp_port=dict(required=False, type="str"), + ftp_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]), + ftp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]), + ftp_status=dict(required=False, type="str", choices=["disable", "enable"]), + ftp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]), + http=dict(required=False, type="dict"), + http_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]), + http_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]), + http_port=dict(required=False, type="str"), + http_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]), + http_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]), + http_ssl=dict(required=False, type="str", choices=["disable", "enable"]), + http_ssl_port=dict(required=False, type="str"), + http_status=dict(required=False, type="str", choices=["disable", "enable"]), + http_tunnel_non_http=dict(required=False, type="str", choices=["disable", "enable"]), + http_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]), + http_unknown_http_version=dict(required=False, type="str", choices=["best-effort", "reject", "tunnel"]), + mapi=dict(required=False, type="dict"), + mapi_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]), + mapi_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]), + mapi_port=dict(required=False, type="str"), + mapi_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]), + mapi_status=dict(required=False, type="str", choices=["disable", "enable"]), + mapi_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]), + tcp=dict(required=False, type="dict"), + tcp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_byte_caching_opt=dict(required=False, type="str", choices=["mem-only", "mem-disk"]), + tcp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_port=dict(required=False, type="str"), + tcp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_ssl=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_ssl_port=dict(required=False, type="str"), + tcp_status=dict(required=False, type="str", choices=["disable", "enable"]), + tcp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "transparent": module.params["transparent"], + "name": module.params["name"], + "comments": module.params["comments"], + "auth-group": module.params["auth_group"], + "cifs": { + "byte-caching": module.params["cifs_byte_caching"], + "log-traffic": module.params["cifs_log_traffic"], + "port": module.params["cifs_port"], + "prefer-chunking": module.params["cifs_prefer_chunking"], + "secure-tunnel": module.params["cifs_secure_tunnel"], + "status": module.params["cifs_status"], + "tunnel-sharing": module.params["cifs_tunnel_sharing"], + }, + "ftp": { + "byte-caching": module.params["ftp_byte_caching"], + "log-traffic": module.params["ftp_log_traffic"], + "port": module.params["ftp_port"], + "prefer-chunking": module.params["ftp_prefer_chunking"], + "secure-tunnel": module.params["ftp_secure_tunnel"], + "status": module.params["ftp_status"], + "tunnel-sharing": module.params["ftp_tunnel_sharing"], + }, + "http": { + "byte-caching": module.params["http_byte_caching"], + "log-traffic": module.params["http_log_traffic"], + "port": module.params["http_port"], + "prefer-chunking": module.params["http_prefer_chunking"], + "secure-tunnel": module.params["http_secure_tunnel"], + "ssl": module.params["http_ssl"], + "ssl-port": module.params["http_ssl_port"], + "status": module.params["http_status"], + "tunnel-non-http": module.params["http_tunnel_non_http"], + "tunnel-sharing": module.params["http_tunnel_sharing"], + "unknown-http-version": module.params["http_unknown_http_version"], + }, + "mapi": { + "byte-caching": module.params["mapi_byte_caching"], + "log-traffic": module.params["mapi_log_traffic"], + "port": module.params["mapi_port"], + "secure-tunnel": module.params["mapi_secure_tunnel"], + "status": module.params["mapi_status"], + "tunnel-sharing": module.params["mapi_tunnel_sharing"], + }, + "tcp": { + "byte-caching": module.params["tcp_byte_caching"], + "byte-caching-opt": module.params["tcp_byte_caching_opt"], + "log-traffic": module.params["tcp_log_traffic"], + "port": module.params["tcp_port"], + "secure-tunnel": module.params["tcp_secure_tunnel"], + "ssl": module.params["tcp_ssl"], + "ssl-port": module.params["tcp_ssl_port"], + "status": module.params["tcp_status"], + "tunnel-sharing": module.params["tcp_tunnel_sharing"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['cifs', 'ftp', 'http', 'mapi', 'tcp'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + + try: + results = fmgr_wanopt_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py new file mode 100644 index 000000000..427cd2e0b --- /dev/null +++ b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py @@ -0,0 +1,1081 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: fmgr_secprof_web +notes: + - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/). +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage web filter security profiles in FortiManager +description: + - Manage web filter security profiles in FortiManager through playbooks using the FMG API + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + youtube_channel_status: + description: + - YouTube channel filter status. + - choice | disable | Disable YouTube channel filter. + - choice | blacklist | Block matches. + - choice | whitelist | Allow matches. + required: false + choices: ["disable", "blacklist", "whitelist"] + + wisp_servers: + description: + - WISP servers. + required: false + + wisp_algorithm: + description: + - WISP server selection algorithm. + - choice | auto-learning | Select the lightest loading healthy server. + - choice | primary-secondary | Select the first healthy server in order. + - choice | round-robin | Select the next healthy server. + required: false + choices: ["auto-learning", "primary-secondary", "round-robin"] + + wisp: + description: + - Enable/disable web proxy WISP. + - choice | disable | Disable web proxy WISP. + - choice | enable | Enable web proxy WISP. + required: false + choices: ["disable", "enable"] + + web_url_log: + description: + - Enable/disable logging URL filtering. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_invalid_domain_log: + description: + - Enable/disable logging invalid domain names. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_ftgd_quota_usage: + description: + - Enable/disable logging daily quota usage. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_ftgd_err_log: + description: + - Enable/disable logging rating errors. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_vbs_log: + description: + - Enable/disable logging VBS scripts. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_unknown_log: + description: + - Enable/disable logging unknown scripts. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_referer_log: + description: + - Enable/disable logging referrers. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_jscript_log: + description: + - Enable/disable logging JScripts. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_js_log: + description: + - Enable/disable logging Java scripts. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_cookie_removal_log: + description: + - Enable/disable logging blocked cookies. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_cookie_log: + description: + - Enable/disable logging cookie filtering. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_command_block_log: + description: + - Enable/disable logging blocked commands. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_applet_log: + description: + - Enable/disable logging Java applets. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_filter_activex_log: + description: + - Enable/disable logging ActiveX. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_extended_all_action_log: + description: + - Enable/disable extended any filter action logging for web filtering. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_content_log: + description: + - Enable/disable logging logging blocked web content. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + replacemsg_group: + description: + - Replacement message group. + required: false + + post_action: + description: + - Action taken for HTTP POST traffic. + - choice | normal | Normal, POST requests are allowed. + - choice | block | POST requests are blocked. + required: false + choices: ["normal", "block"] + + ovrd_perm: + description: + - FLAG Based Options. Specify multiple in list form. + - flag | bannedword-override | Banned word override. + - flag | urlfilter-override | URL filter override. + - flag | fortiguard-wf-override | FortiGuard Web Filter override. + - flag | contenttype-check-override | Content-type header override. + required: false + choices: + - bannedword-override + - urlfilter-override + - fortiguard-wf-override + - contenttype-check-override + + options: + description: + - FLAG Based Options. Specify multiple in list form. + - flag | block-invalid-url | Block sessions contained an invalid domain name. + - flag | jscript | Javascript block. + - flag | js | JS block. + - flag | vbs | VB script block. + - flag | unknown | Unknown script block. + - flag | wf-referer | Referring block. + - flag | intrinsic | Intrinsic script block. + - flag | wf-cookie | Cookie block. + - flag | per-user-bwl | Per-user black/white list filter + - flag | activexfilter | ActiveX filter. + - flag | cookiefilter | Cookie filter. + - flag | javafilter | Java applet filter. + required: false + choices: + - block-invalid-url + - jscript + - js + - vbs + - unknown + - wf-referer + - intrinsic + - wf-cookie + - per-user-bwl + - activexfilter + - cookiefilter + - javafilter + + name: + description: + - Profile name. + required: false + + log_all_url: + description: + - Enable/disable logging all URLs visited. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + inspection_mode: + description: + - Web filtering inspection mode. + - choice | proxy | Proxy. + - choice | flow-based | Flow based. + required: false + choices: ["proxy", "flow-based"] + + https_replacemsg: + description: + - Enable replacement messages for HTTPS. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + extended_log: + description: + - Enable/disable extended logging for web filtering. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + comment: + description: + - Optional comments. + required: false + + ftgd_wf: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + ftgd_wf_exempt_quota: + description: + - Do not stop quota for these categories. + required: false + + ftgd_wf_max_quota_timeout: + description: + - Maximum FortiGuard quota used by single page view in seconds (excludes streams). + required: false + + ftgd_wf_options: + description: + - Options for FortiGuard Web Filter. + - FLAG Based Options. Specify multiple in list form. + - flag | error-allow | Allow web pages with a rating error to pass through. + - flag | rate-server-ip | Rate the server IP in addition to the domain name. + - flag | connect-request-bypass | Bypass connection which has CONNECT request. + - flag | ftgd-disable | Disable FortiGuard scanning. + required: false + choices: ["error-allow", "rate-server-ip", "connect-request-bypass", "ftgd-disable"] + + ftgd_wf_ovrd: + description: + - Allow web filter profile overrides. + required: false + + ftgd_wf_rate_crl_urls: + description: + - Enable/disable rating CRL by URL. + - choice | disable | Disable rating CRL by URL. + - choice | enable | Enable rating CRL by URL. + required: false + choices: ["disable", "enable"] + + ftgd_wf_rate_css_urls: + description: + - Enable/disable rating CSS by URL. + - choice | disable | Disable rating CSS by URL. + - choice | enable | Enable rating CSS by URL. + required: false + choices: ["disable", "enable"] + + ftgd_wf_rate_image_urls: + description: + - Enable/disable rating images by URL. + - choice | disable | Disable rating images by URL (blocked images are replaced with blanks). + - choice | enable | Enable rating images by URL (blocked images are replaced with blanks). + required: false + choices: ["disable", "enable"] + + ftgd_wf_rate_javascript_urls: + description: + - Enable/disable rating JavaScript by URL. + - choice | disable | Disable rating JavaScript by URL. + - choice | enable | Enable rating JavaScript by URL. + required: false + choices: ["disable", "enable"] + + ftgd_wf_filters_action: + description: + - Action to take for matches. + - choice | block | Block access. + - choice | monitor | Allow access while logging the action. + - choice | warning | Allow access after warning the user. + - choice | authenticate | Authenticate user before allowing access. + required: false + choices: ["block", "monitor", "warning", "authenticate"] + + ftgd_wf_filters_auth_usr_grp: + description: + - Groups with permission to authenticate. + required: false + + ftgd_wf_filters_category: + description: + - Categories and groups the filter examines. + required: false + + ftgd_wf_filters_log: + description: + - Enable/disable logging. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + ftgd_wf_filters_override_replacemsg: + description: + - Override replacement message. + required: false + + ftgd_wf_filters_warn_duration: + description: + - Duration of warnings. + required: false + + ftgd_wf_filters_warning_duration_type: + description: + - Re-display warning after closing browser or after a timeout. + - choice | session | After session ends. + - choice | timeout | After timeout occurs. + required: false + choices: ["session", "timeout"] + + ftgd_wf_filters_warning_prompt: + description: + - Warning prompts in each category or each domain. + - choice | per-domain | Per-domain warnings. + - choice | per-category | Per-category warnings. + required: false + choices: ["per-domain", "per-category"] + + ftgd_wf_quota_category: + description: + - FortiGuard categories to apply quota to (category action must be set to monitor). + required: false + + ftgd_wf_quota_duration: + description: + - Duration of quota. + required: false + + ftgd_wf_quota_override_replacemsg: + description: + - Override replacement message. + required: false + + ftgd_wf_quota_type: + description: + - Quota type. + - choice | time | Use a time-based quota. + - choice | traffic | Use a traffic-based quota. + required: false + choices: ["time", "traffic"] + + ftgd_wf_quota_unit: + description: + - Traffic quota unit of measurement. + - choice | B | Quota in bytes. + - choice | KB | Quota in kilobytes. + - choice | MB | Quota in megabytes. + - choice | GB | Quota in gigabytes. + required: false + choices: ["B", "KB", "MB", "GB"] + + ftgd_wf_quota_value: + description: + - Traffic quota value. + required: false + + override: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + override_ovrd_cookie: + description: + - Allow/deny browser-based (cookie) overrides. + - choice | deny | Deny browser-based (cookie) override. + - choice | allow | Allow browser-based (cookie) override. + required: false + choices: ["deny", "allow"] + + override_ovrd_dur: + description: + - Override duration. + required: false + + override_ovrd_dur_mode: + description: + - Override duration mode. + - choice | constant | Constant mode. + - choice | ask | Prompt for duration when initiating an override. + required: false + choices: ["constant", "ask"] + + override_ovrd_scope: + description: + - Override scope. + - choice | user | Override for the user. + - choice | user-group | Override for the user's group. + - choice | ip | Override for the initiating IP. + - choice | ask | Prompt for scope when initiating an override. + - choice | browser | Create browser-based (cookie) override. + required: false + choices: ["user", "user-group", "ip", "ask", "browser"] + + override_ovrd_user_group: + description: + - User groups with permission to use the override. + required: false + + override_profile: + description: + - Web filter profile with permission to create overrides. + required: false + + override_profile_attribute: + description: + - Profile attribute to retrieve from the RADIUS server. + - choice | User-Name | Use this attribute. + - choice | NAS-IP-Address | Use this attribute. + - choice | Framed-IP-Address | Use this attribute. + - choice | Framed-IP-Netmask | Use this attribute. + - choice | Filter-Id | Use this attribute. + - choice | Login-IP-Host | Use this attribute. + - choice | Reply-Message | Use this attribute. + - choice | Callback-Number | Use this attribute. + - choice | Callback-Id | Use this attribute. + - choice | Framed-Route | Use this attribute. + - choice | Framed-IPX-Network | Use this attribute. + - choice | Class | Use this attribute. + - choice | Called-Station-Id | Use this attribute. + - choice | Calling-Station-Id | Use this attribute. + - choice | NAS-Identifier | Use this attribute. + - choice | Proxy-State | Use this attribute. + - choice | Login-LAT-Service | Use this attribute. + - choice | Login-LAT-Node | Use this attribute. + - choice | Login-LAT-Group | Use this attribute. + - choice | Framed-AppleTalk-Zone | Use this attribute. + - choice | Acct-Session-Id | Use this attribute. + - choice | Acct-Multi-Session-Id | Use this attribute. + required: false + choices: + - User-Name + - NAS-IP-Address + - Framed-IP-Address + - Framed-IP-Netmask + - Filter-Id + - Login-IP-Host + - Reply-Message + - Callback-Number + - Callback-Id + - Framed-Route + - Framed-IPX-Network + - Class + - Called-Station-Id + - Calling-Station-Id + - NAS-Identifier + - Proxy-State + - Login-LAT-Service + - Login-LAT-Node + - Login-LAT-Group + - Framed-AppleTalk-Zone + - Acct-Session-Id + - Acct-Multi-Session-Id + + override_profile_type: + description: + - Override profile type. + - choice | list | Profile chosen from list. + - choice | radius | Profile determined by RADIUS server. + required: false + choices: ["list", "radius"] + + url_extraction: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + url_extraction_redirect_header: + description: + - HTTP header name to use for client redirect on blocked requests + required: false + + url_extraction_redirect_no_content: + description: + - Enable / Disable empty message-body entity in HTTP response + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + url_extraction_redirect_url: + description: + - HTTP header value to use for client redirect on blocked requests + required: false + + url_extraction_server_fqdn: + description: + - URL extraction server FQDN (fully qualified domain name) + required: false + + url_extraction_status: + description: + - Enable URL Extraction + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + web_blacklist: + description: + - Enable/disable automatic addition of URLs detected by FortiSandbox to blacklist. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_bword_table: + description: + - Banned word table ID. + required: false + + web_bword_threshold: + description: + - Banned word score threshold. + required: false + + web_content_header_list: + description: + - Content header list. + required: false + + web_keyword_match: + description: + - Search keywords to log when match is found. + required: false + + web_log_search: + description: + - Enable/disable logging all search phrases. + - choice | disable | Disable setting. + - choice | enable | Enable setting. + required: false + choices: ["disable", "enable"] + + web_safe_search: + description: + - Safe search type. + - FLAG Based Options. Specify multiple in list form. + - flag | url | Insert safe search string into URL. + - flag | header | Insert safe search header. + required: false + choices: ["url", "header"] + + web_urlfilter_table: + description: + - URL filter table ID. + required: false + + web_whitelist: + description: + - FortiGuard whitelist settings. + - FLAG Based Options. Specify multiple in list form. + - flag | exempt-av | Exempt antivirus. + - flag | exempt-webcontent | Exempt web content. + - flag | exempt-activex-java-cookie | Exempt ActiveX-JAVA-Cookie. + - flag | exempt-dlp | Exempt DLP. + - flag | exempt-rangeblock | Exempt RangeBlock. + - flag | extended-log-others | Support extended log. + required: false + choices: + - exempt-av + - exempt-webcontent + - exempt-activex-java-cookie + - exempt-dlp + - exempt-rangeblock + - extended-log-others + + web_youtube_restrict: + description: + - YouTube EDU filter level. + - choice | strict | Strict access for YouTube. + - choice | none | Full access for YouTube. + - choice | moderate | Moderate access for YouTube. + required: false + choices: ["strict", "none", "moderate"] + + youtube_channel_filter: + description: + - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED! + - List of multiple child objects to be added. Expects a list of dictionaries. + - Dictionaries must use FortiManager API parameters, not the ansible ones listed below. + - If submitted, all other prefixed sub-parameters ARE IGNORED. + - This object is MUTUALLY EXCLUSIVE with its options. + - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide. + - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS + required: false + + youtube_channel_filter_channel_id: + description: + - YouTube channel ID to be filtered. + required: false + + youtube_channel_filter_comment: + description: + - Comment. + required: false + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + community.fortios.fmgr_secprof_web: + name: "Ansible_Web_Filter_Profile" + mode: "delete" + + - name: CREATE Profile + community.fortios.fmgr_secprof_web: + name: "Ansible_Web_Filter_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + extended_log: "enable" + inspection_mode: "proxy" + log_all_url: "enable" + options: "js" + ovrd_perm: "bannedword-override" + post_action: "block" + web_content_log: "enable" + web_extended_all_action_log: "enable" + web_filter_activex_log: "enable" + web_filter_applet_log: "enable" + web_filter_command_block_log: "enable" + web_filter_cookie_log: "enable" + web_filter_cookie_removal_log: "enable" + web_filter_js_log: "enable" + web_filter_jscript_log: "enable" + web_filter_referer_log: "enable" + web_filter_unknown_log: "enable" + web_filter_vbs_log: "enable" + web_ftgd_err_log: "enable" + web_ftgd_quota_usage: "enable" + web_invalid_domain_log: "enable" + web_url_log: "enable" + wisp: "enable" + wisp_algorithm: "auto-learning" + youtube_channel_status: "blacklist" +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: str +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.connection import Connection +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict + + +def fmgr_webfilter_profile_modify(fmgr, paramgram): + + mode = paramgram["mode"] + adom = paramgram["adom"] + + response = DEFAULT_RESULT_OBJ + url = "" + datagram = {} + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/webfilter/profile'.format(adom=adom) + datagram = scrub_dict(prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/webfilter/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + response = fmgr.process_request(url, datagram, paramgram["mode"]) + + return response + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + youtube_channel_status=dict(required=False, type="str", choices=["disable", "blacklist", "whitelist"]), + wisp_servers=dict(required=False, type="str"), + wisp_algorithm=dict(required=False, type="str", choices=["auto-learning", "primary-secondary", "round-robin"]), + wisp=dict(required=False, type="str", choices=["disable", "enable"]), + web_url_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_invalid_domain_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_ftgd_quota_usage=dict(required=False, type="str", choices=["disable", "enable"]), + web_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_vbs_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_unknown_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_referer_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_jscript_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_js_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_cookie_removal_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_command_block_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_applet_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_filter_activex_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_extended_all_action_log=dict(required=False, type="str", choices=["disable", "enable"]), + web_content_log=dict(required=False, type="str", choices=["disable", "enable"]), + replacemsg_group=dict(required=False, type="str"), + post_action=dict(required=False, type="str", choices=["normal", "block"]), + ovrd_perm=dict(required=False, type="list", choices=["bannedword-override", + "urlfilter-override", + "fortiguard-wf-override", + "contenttype-check-override"]), + options=dict(required=False, type="list", choices=["block-invalid-url", + "jscript", + "js", + "vbs", + "unknown", + "wf-referer", + "intrinsic", + "wf-cookie", + "per-user-bwl", + "activexfilter", + "cookiefilter", + "javafilter"]), + name=dict(required=False, type="str"), + log_all_url=dict(required=False, type="str", choices=["disable", "enable"]), + inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]), + https_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]), + extended_log=dict(required=False, type="str", choices=["disable", "enable"]), + comment=dict(required=False, type="str"), + ftgd_wf=dict(required=False, type="list"), + ftgd_wf_exempt_quota=dict(required=False, type="str"), + ftgd_wf_max_quota_timeout=dict(required=False, type="int"), + ftgd_wf_options=dict(required=False, type="str", choices=["error-allow", "rate-server-ip", + "connect-request-bypass", "ftgd-disable"]), + ftgd_wf_ovrd=dict(required=False, type="str"), + ftgd_wf_rate_crl_urls=dict(required=False, type="str", choices=["disable", "enable"]), + ftgd_wf_rate_css_urls=dict(required=False, type="str", choices=["disable", "enable"]), + ftgd_wf_rate_image_urls=dict(required=False, type="str", choices=["disable", "enable"]), + ftgd_wf_rate_javascript_urls=dict(required=False, type="str", choices=["disable", "enable"]), + + ftgd_wf_filters_action=dict(required=False, type="str", choices=["block", "monitor", + "warning", "authenticate"]), + ftgd_wf_filters_auth_usr_grp=dict(required=False, type="str"), + ftgd_wf_filters_category=dict(required=False, type="str"), + ftgd_wf_filters_log=dict(required=False, type="str", choices=["disable", "enable"]), + ftgd_wf_filters_override_replacemsg=dict(required=False, type="str"), + ftgd_wf_filters_warn_duration=dict(required=False, type="str"), + ftgd_wf_filters_warning_duration_type=dict(required=False, type="str", choices=["session", "timeout"]), + ftgd_wf_filters_warning_prompt=dict(required=False, type="str", choices=["per-domain", "per-category"]), + + ftgd_wf_quota_category=dict(required=False, type="str"), + ftgd_wf_quota_duration=dict(required=False, type="str"), + ftgd_wf_quota_override_replacemsg=dict(required=False, type="str"), + ftgd_wf_quota_type=dict(required=False, type="str", choices=["time", "traffic"]), + ftgd_wf_quota_unit=dict(required=False, type="str", choices=["B", "KB", "MB", "GB"]), + ftgd_wf_quota_value=dict(required=False, type="int"), + override=dict(required=False, type="list"), + override_ovrd_cookie=dict(required=False, type="str", choices=["deny", "allow"]), + override_ovrd_dur=dict(required=False, type="str"), + override_ovrd_dur_mode=dict(required=False, type="str", choices=["constant", "ask"]), + override_ovrd_scope=dict(required=False, type="str", choices=["user", "user-group", "ip", "ask", "browser"]), + override_ovrd_user_group=dict(required=False, type="str"), + override_profile=dict(required=False, type="str"), + override_profile_attribute=dict(required=False, type="list", choices=["User-Name", + "NAS-IP-Address", + "Framed-IP-Address", + "Framed-IP-Netmask", + "Filter-Id", + "Login-IP-Host", + "Reply-Message", + "Callback-Number", + "Callback-Id", + "Framed-Route", + "Framed-IPX-Network", + "Class", + "Called-Station-Id", + "Calling-Station-Id", + "NAS-Identifier", + "Proxy-State", + "Login-LAT-Service", + "Login-LAT-Node", + "Login-LAT-Group", + "Framed-AppleTalk-Zone", + "Acct-Session-Id", + "Acct-Multi-Session-Id"]), + override_profile_type=dict(required=False, type="str", choices=["list", "radius"]), + url_extraction=dict(required=False, type="list"), + url_extraction_redirect_header=dict(required=False, type="str"), + url_extraction_redirect_no_content=dict(required=False, type="str", choices=["disable", "enable"]), + url_extraction_redirect_url=dict(required=False, type="str"), + url_extraction_server_fqdn=dict(required=False, type="str"), + url_extraction_status=dict(required=False, type="str", choices=["disable", "enable"]), + web=dict(required=False, type="list"), + web_blacklist=dict(required=False, type="str", choices=["disable", "enable"]), + web_bword_table=dict(required=False, type="str"), + web_bword_threshold=dict(required=False, type="int"), + web_content_header_list=dict(required=False, type="str"), + web_keyword_match=dict(required=False, type="str"), + web_log_search=dict(required=False, type="str", choices=["disable", "enable"]), + web_safe_search=dict(required=False, type="str", choices=["url", "header"]), + web_urlfilter_table=dict(required=False, type="str"), + web_whitelist=dict(required=False, type="list", choices=["exempt-av", + "exempt-webcontent", + "exempt-activex-java-cookie", + "exempt-dlp", + "exempt-rangeblock", + "extended-log-others"]), + web_youtube_restrict=dict(required=False, type="str", choices=["strict", "none", "moderate"]), + youtube_channel_filter=dict(required=False, type="list"), + youtube_channel_filter_channel_id=dict(required=False, type="str"), + youtube_channel_filter_comment=dict(required=False, type="str"), + + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, ) + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "youtube-channel-status": module.params["youtube_channel_status"], + "wisp-servers": module.params["wisp_servers"], + "wisp-algorithm": module.params["wisp_algorithm"], + "wisp": module.params["wisp"], + "web-url-log": module.params["web_url_log"], + "web-invalid-domain-log": module.params["web_invalid_domain_log"], + "web-ftgd-quota-usage": module.params["web_ftgd_quota_usage"], + "web-ftgd-err-log": module.params["web_ftgd_err_log"], + "web-filter-vbs-log": module.params["web_filter_vbs_log"], + "web-filter-unknown-log": module.params["web_filter_unknown_log"], + "web-filter-referer-log": module.params["web_filter_referer_log"], + "web-filter-jscript-log": module.params["web_filter_jscript_log"], + "web-filter-js-log": module.params["web_filter_js_log"], + "web-filter-cookie-removal-log": module.params["web_filter_cookie_removal_log"], + "web-filter-cookie-log": module.params["web_filter_cookie_log"], + "web-filter-command-block-log": module.params["web_filter_command_block_log"], + "web-filter-applet-log": module.params["web_filter_applet_log"], + "web-filter-activex-log": module.params["web_filter_activex_log"], + "web-extended-all-action-log": module.params["web_extended_all_action_log"], + "web-content-log": module.params["web_content_log"], + "replacemsg-group": module.params["replacemsg_group"], + "post-action": module.params["post_action"], + "ovrd-perm": module.params["ovrd_perm"], + "options": module.params["options"], + "name": module.params["name"], + "log-all-url": module.params["log_all_url"], + "inspection-mode": module.params["inspection_mode"], + "https-replacemsg": module.params["https_replacemsg"], + "extended-log": module.params["extended_log"], + "comment": module.params["comment"], + "ftgd-wf": { + "exempt-quota": module.params["ftgd_wf_exempt_quota"], + "max-quota-timeout": module.params["ftgd_wf_max_quota_timeout"], + "options": module.params["ftgd_wf_options"], + "ovrd": module.params["ftgd_wf_ovrd"], + "rate-crl-urls": module.params["ftgd_wf_rate_crl_urls"], + "rate-css-urls": module.params["ftgd_wf_rate_css_urls"], + "rate-image-urls": module.params["ftgd_wf_rate_image_urls"], + "rate-javascript-urls": module.params["ftgd_wf_rate_javascript_urls"], + "filters": { + "action": module.params["ftgd_wf_filters_action"], + "auth-usr-grp": module.params["ftgd_wf_filters_auth_usr_grp"], + "category": module.params["ftgd_wf_filters_category"], + "log": module.params["ftgd_wf_filters_log"], + "override-replacemsg": module.params["ftgd_wf_filters_override_replacemsg"], + "warn-duration": module.params["ftgd_wf_filters_warn_duration"], + "warning-duration-type": module.params["ftgd_wf_filters_warning_duration_type"], + "warning-prompt": module.params["ftgd_wf_filters_warning_prompt"], + }, + "quota": { + "category": module.params["ftgd_wf_quota_category"], + "duration": module.params["ftgd_wf_quota_duration"], + "override-replacemsg": module.params["ftgd_wf_quota_override_replacemsg"], + "type": module.params["ftgd_wf_quota_type"], + "unit": module.params["ftgd_wf_quota_unit"], + "value": module.params["ftgd_wf_quota_value"], + }, + }, + "override": { + "ovrd-cookie": module.params["override_ovrd_cookie"], + "ovrd-dur": module.params["override_ovrd_dur"], + "ovrd-dur-mode": module.params["override_ovrd_dur_mode"], + "ovrd-scope": module.params["override_ovrd_scope"], + "ovrd-user-group": module.params["override_ovrd_user_group"], + "profile": module.params["override_profile"], + "profile-attribute": module.params["override_profile_attribute"], + "profile-type": module.params["override_profile_type"], + }, + "url-extraction": { + "redirect-header": module.params["url_extraction_redirect_header"], + "redirect-no-content": module.params["url_extraction_redirect_no_content"], + "redirect-url": module.params["url_extraction_redirect_url"], + "server-fqdn": module.params["url_extraction_server_fqdn"], + "status": module.params["url_extraction_status"], + }, + "web": { + "blacklist": module.params["web_blacklist"], + "bword-table": module.params["web_bword_table"], + "bword-threshold": module.params["web_bword_threshold"], + "content-header-list": module.params["web_content_header_list"], + "keyword-match": module.params["web_keyword_match"], + "log-search": module.params["web_log_search"], + "safe-search": module.params["web_safe_search"], + "urlfilter-table": module.params["web_urlfilter_table"], + "whitelist": module.params["web_whitelist"], + "youtube-restrict": module.params["web_youtube_restrict"], + }, + "youtube-channel-filter": { + "channel-id": module.params["youtube_channel_filter_channel_id"], + "comment": module.params["youtube_channel_filter_comment"], + } + } + module.paramgram = paramgram + fmgr = None + if module._socket_path: + connection = Connection(module._socket_path) + fmgr = FortiManagerHandler(connection, module) + fmgr.tools = FMGRCommon() + else: + module.fail_json(**FAIL_SOCKET_MSG) + + list_overrides = ['ftgd-wf', 'override', 'url-extraction', 'web', 'youtube-channel-filter'] + paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides, + paramgram=paramgram, module=module) + + results = DEFAULT_RESULT_OBJ + + try: + + results = fmgr_webfilter_profile_modify(fmgr, paramgram) + fmgr.govern_response(module=module, results=results, + ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram)) + + except Exception as err: + raise FMGBaseException(err) + + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/fortios/tests/requirements.yml b/ansible_collections/community/fortios/tests/requirements.yml new file mode 100644 index 000000000..36ee27096 --- /dev/null +++ b/ansible_collections/community/fortios/tests/requirements.yml @@ -0,0 +1,2 @@ +unit_tests_dependencies: +- fortinet.fortios diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt new file mode 100644 index 000000000..4a289a0fb --- /dev/null +++ b/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt @@ -0,0 +1,51 @@ +plugins/modules/faz_device.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_group.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_provision_template.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device_provision_template.py validate-modules:invalid-argument-name +plugins/modules/fmgr_device_provision_template.py validate-modules:nonexistent-parameter-documented +plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_package.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type +plugins/modules/fmgr_provisioning.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_query.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec +plugins/modules/fmgr_script.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_av.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_web.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt new file mode 100644 index 000000000..4a289a0fb --- /dev/null +++ b/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt @@ -0,0 +1,51 @@ +plugins/modules/faz_device.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_group.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_provision_template.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_device_provision_template.py validate-modules:invalid-argument-name +plugins/modules/fmgr_device_provision_template.py validate-modules:nonexistent-parameter-documented +plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_package.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type +plugins/modules/fmgr_provisioning.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_query.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec +plugins/modules/fmgr_script.py validate-modules:doc-required-mismatch +plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_av.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_web.py validate-modules:parameter-list-no-elements +plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt new file mode 100644 index 000000000..fc1eac658 --- /dev/null +++ b/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt @@ -0,0 +1,29 @@ +plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type +plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec +plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc +plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc diff --git a/ansible_collections/community/fortios/tests/unit/compat/__init__.py b/ansible_collections/community/fortios/tests/unit/compat/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/compat/__init__.py diff --git a/ansible_collections/community/fortios/tests/unit/compat/mock.py b/ansible_collections/community/fortios/tests/unit/compat/mock.py new file mode 100644 index 000000000..0972cd2e8 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/compat/mock.py @@ -0,0 +1,122 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +''' +Compat module for Python3.x's unittest.mock module +''' +import sys + +# Python 2.7 + +# Note: Could use the pypi mock library on python3.x as well as python2.x. It +# is the same as the python3 stdlib mock library + +try: + # Allow wildcard import because we really do want to import all of mock's + # symbols into this compat shim + # pylint: disable=wildcard-import,unused-wildcard-import + from unittest.mock import * +except ImportError: + # Python 2 + # pylint: disable=wildcard-import,unused-wildcard-import + try: + from mock import * + except ImportError: + print('You need the mock library installed on python2.x to run tests') + + +# Prior to 3.4.4, mock_open cannot handle binary read_data +if sys.version_info >= (3,) and sys.version_info < (3, 4, 4): + file_spec = None + + def _iterate_read_data(read_data): + # Helper for mock_open: + # Retrieve lines from read_data via a generator so that separate calls to + # readline, read, and readlines are properly interleaved + sep = b'\n' if isinstance(read_data, bytes) else '\n' + data_as_list = [l + sep for l in read_data.split(sep)] + + if data_as_list[-1] == sep: + # If the last line ended in a newline, the list comprehension will have an + # extra entry that's just a newline. Remove this. + data_as_list = data_as_list[:-1] + else: + # If there wasn't an extra newline by itself, then the file being + # emulated doesn't have a newline to end the last line remove the + # newline that our naive format() added + data_as_list[-1] = data_as_list[-1][:-1] + + for line in data_as_list: + yield line + + def mock_open(mock=None, read_data=''): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` methoddline`, and `readlines` of the + file handle to return. This is an empty string by default. + """ + def _readlines_side_effect(*args, **kwargs): + if handle.readlines.return_value is not None: + return handle.readlines.return_value + return list(_data) + + def _read_side_effect(*args, **kwargs): + if handle.read.return_value is not None: + return handle.read.return_value + return type(read_data)().join(_data) + + def _readline_side_effect(): + if handle.readline.return_value is not None: + while True: + yield handle.readline.return_value + for line in _data: + yield line + + global file_spec + if file_spec is None: + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + if mock is None: + mock = MagicMock(name='open', spec=open) + + handle = MagicMock(spec=file_spec) + handle.__enter__.return_value = handle + + _data = _iterate_read_data(read_data) + + handle.write.return_value = None + handle.read.return_value = None + handle.readline.return_value = None + handle.readlines.return_value = None + + handle.read.side_effect = _read_side_effect + handle.readline.side_effect = _readline_side_effect() + handle.readlines.side_effect = _readlines_side_effect + + mock.return_value = handle + return mock diff --git a/ansible_collections/community/fortios/tests/unit/compat/unittest.py b/ansible_collections/community/fortios/tests/unit/compat/unittest.py new file mode 100644 index 000000000..98f08ad6a --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/compat/unittest.py @@ -0,0 +1,38 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +''' +Compat module for Python2.7's unittest module +''' + +import sys + +# Allow wildcard import because we really do want to import all of +# unittests's symbols into this compat shim +# pylint: disable=wildcard-import,unused-wildcard-import +if sys.version_info < (2, 7): + try: + # Need unittest2 on python2.6 + from unittest2 import * + except ImportError: + print('You need unittest2 installed on python2.6.x to run tests') +else: + from unittest import * diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json new file mode 100644 index 000000000..90dba75f0 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json @@ -0,0 +1,934 @@ +{ + "add_device": [ + { + "url": "/dvm/cmd/add/device/", + "raw_response": { + "device": { + "adm_pass": "fortinet", + "os_ver": 6, + "ip": "10.7.220.151", + "mgmt.__data[6]": 1, + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "platform_id": 112, + "branch_pt": 231, + "hostname": "ansible-fgt01", + "source": 1, + "mgmt_id": 1014939351, + "version": 600, + "build": 231, + "mgmt_mode": 3, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "mgmt.__data[4]": 1052262400, + "oid": 403, + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698141, + "vm_mem_limit": 6144, + "mgmt.__data[0]": 3870643, + "name": "FGT1", + "tab_status": "<unknown>", + "patch": 4, + "vm_cpu_limit": 4, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097169, + "sn": "FGVM04TM18000391", + "mr": 0, + "os_type": 0, + "vm_cpu": 1 + } + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "name": "FGT1", + "ip": "10.7.220.151", + "flags": 24, + "sn": null, + "mgmt_mode": "fmgfaz", + "adm_usr": "admin" + }, + "flags": [ + "create_task", + "nonblocking" + ], + "odd_request_form": "True", + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.151", + "device_unique_name": "FGT1", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "exec" + }, + { + "url": "/dvm/cmd/add/device/", + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.152", + "device_unique_name": "FGT2", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "name": "FGT2", + "ip": "10.7.220.152", + "flags": 24, + "sn": null, + "mgmt_mode": "fmgfaz", + "adm_usr": "admin" + }, + "flags": [ + "create_task", + "nonblocking" + ], + "odd_request_form": "True", + "adom": "ansible" + }, + "raw_response": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.152", + "mgmt.__data[6]": 1, + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "vm_cpu_limit": 4, + "vm_cpu": 1, + "branch_pt": 231, + "hostname": "ansible-fgt02", + "source": 1, + "mgmt_id": 1879100317, + "version": 600, + "build": 231, + "mgmt_mode": 3, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "oid": 415, + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698177, + "patch": 4, + "vm_mem_limit": 6144, + "mgmt.__data[0]": 3870643, + "name": "FGT2", + "tab_status": "<unknown>", + "mgmt.__data[4]": 1052262400, + "platform_id": 112, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097169, + "sn": "FGVM04TM18000392", + "mr": 0, + "os_type": 0, + "os_ver": 6 + } + }, + "post_method": "exec" + }, + { + "url": "/dvm/cmd/add/device/", + "raw_response": { + "device": { + "adm_pass": "fortinet", + "os_ver": 6, + "ip": "10.7.220.153", + "mgmt.__data[6]": 1, + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "platform_id": 112, + "branch_pt": 231, + "hostname": "ansible-fgt03", + "source": 1, + "mgmt_id": 104863251, + "version": 600, + "build": 231, + "mgmt_mode": 3, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "mgmt.__data[4]": 1052262400, + "oid": 427, + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698204, + "vm_mem_limit": 6144, + "mgmt.__data[0]": 3870643, + "name": "FGT3", + "tab_status": "<unknown>", + "patch": 4, + "vm_cpu_limit": 4, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097169, + "sn": "FGVM04TM18000393", + "mr": 0, + "os_type": 0, + "vm_cpu": 1 + } + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "name": "FGT3", + "ip": "10.7.220.153", + "flags": 24, + "sn": null, + "mgmt_mode": "fmgfaz", + "adm_usr": "admin" + }, + "flags": [ + "create_task", + "nonblocking" + ], + "odd_request_form": "True", + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.153", + "device_unique_name": "FGT3", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "exec" + } + ], + "discover_device": [ + { + "url": "/dvm/cmd/discover/device/", + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.151", + "device_unique_name": "FGT1", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.151", + "adm_usr": "admin" + }, + "odd_request_form": "True" + }, + "raw_response": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.151", + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "vm_cpu_limit": 4, + "vm_cpu": 1, + "branch_pt": 231, + "hostname": "ansible-fgt01", + "source": 1, + "version": 600, + "build": 231, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698136, + "vm_mem_limit": 6144, + "name": "ansible-fgt01", + "tab_status": "<unknown>", + "patch": 4, + "platform_id": 112, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097153, + "sn": "FGVM04TM18000391", + "mr": 0, + "os_type": 0, + "os_ver": 6 + } + }, + "post_method": "exec" + }, + { + "url": "/dvm/cmd/discover/device/", + "raw_response": { + "device": { + "adm_pass": "fortinet", + "os_ver": 6, + "ip": "10.7.220.152", + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "platform_id": 112, + "branch_pt": 231, + "hostname": "ansible-fgt02", + "source": 1, + "version": 600, + "build": 231, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698173, + "vm_mem_limit": 6144, + "name": "ansible-fgt02", + "tab_status": "<unknown>", + "patch": 4, + "vm_cpu_limit": 4, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097153, + "sn": "FGVM04TM18000392", + "mr": 0, + "os_type": 0, + "vm_cpu": 1 + } + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.152", + "adm_usr": "admin" + }, + "odd_request_form": "True" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.152", + "device_unique_name": "FGT2", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "exec" + }, + { + "url": "/dvm/cmd/discover/device/", + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.153", + "device_unique_name": "FGT3", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.153", + "adm_usr": "admin" + }, + "odd_request_form": "True" + }, + "raw_response": { + "device": { + "adm_pass": "fortinet", + "ip": "10.7.220.153", + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": 1, + "vm_cpu_limit": 4, + "vm_cpu": 1, + "branch_pt": 231, + "hostname": "ansible-fgt03", + "source": 1, + "version": 600, + "build": 231, + "adm_usr": "admin", + "av_ver": "1.00000(2018-04-09 18:07)", + "conn_status": 1, + "beta": -1, + "dev_status": 1, + "platform_str": "FortiGate-VM64", + "last_checked": 1550698200, + "vm_mem_limit": 6144, + "name": "ansible-fgt03", + "tab_status": "<unknown>", + "patch": 4, + "platform_id": 112, + "vm_status": 3, + "ips_ver": "6.00741(2015-12-01 02:30)", + "flags": 2097153, + "sn": "FGVM04TM18000393", + "mr": 0, + "os_type": 0, + "os_ver": 6 + } + }, + "post_method": "exec" + } + ], + "get_device": [ + { + "url": "/dvmdb/adom/ansible/device/FGT1", + "raw_response": { + "adm_pass": [ + "ENC", + "tUEPOPpQM6XsNwOPcWyrWoPoKo2DMjtFqOYEzLfF+99FpTkDmKa+GTmwBMLV1ns0OYrNgWnk6RPbRjSZSvu2LPYvCcWfQONLEZ1HlczZ00kEtDRCvRxG6l7FGtcj1Pl7QO9khy2lKWx4/lbPmLNqCzwCmlkAO5fGXR3nCbWPXH5BrRwO" + ], + "faz.perm": 0, + "foslic_ram": 0, + "foslic_type": "temporary", + "last_checked": 1550635232, + "psk": "", + "opts": 0, + "ip": "10.7.220.151", + "foslic_utm": null, + "logdisk_size": 30235, + "mgmt.__data[6]": 1, + "foslic_last_sync": 0, + "app_ver": "", + "ips_ext": 0, + "vm_mem": 1003, + "mgmt.__data[4]": 1052262400, + "maxvdom": 10, + "conn_mode": "passive", + "location_from": "GUI(10.0.0.151)", + "mgmt.__data[1]": 0, + "mgmt.__data[2]": 0, + "faz.full_act": 0, + "os_ver": "6.0", + "node_flags": 0, + "hostname": "ansible-fgt01", + "mgmt.__data[5]": 0, + "mgmt_id": 2076985412, + "hw_rev_minor": 0, + "mgmt_if": "port1", + "source": "faz", + "ha_mode": "standalone", + "version": 600, + "build": 231, + "latitude": "47.473991", + "foslic_cpu": 0, + "last_resync": 1550634702, + "desc": "", + "adm_usr": "admin", + "vm_lic_expire": 0, + "ha_slave": null, + "av_ver": "1.00000(2018-04-09 18:07)", + "fsw_cnt": 0, + "tunnel_cookie": "", + "foslic_inst_time": 0, + "lic_flags": 0, + "checksum": "89 1f b7 b7 2a a6 af 54 c5 a5 aa e3 32 92 c7 55", + "oid": 366, + "conn_status": "up", + "fex_cnt": 0, + "mgmt.__data[3]": 0, + "beta": -1, + "ha_group_name": "", + "dev_status": "installed", + "platform_str": "FortiGate-VM64", + "mgmt.__data[7]": 0, + "faz.used": 0, + "fap_cnt": 0, + "foslic_dr_site": "disable", + "mgmt_mode": "fmgfaz", + "vdom": [ + { + "status": null, + "oid": 3, + "name": "root", + "node_flags": 0, + "devid": "FGT1", + "tab_status": null, + "comments": "", + "flags": null, + "opmode": "nat", + "ext_flags": 1, + "rtm_prof_id": 0 + } + ], + "hdisk_size": 30720, + "vm_mem_limit": 6144, + "mgmt.__data[0]": 3870643, + "ha_group_id": 0, + "name": "FGT1", + "faz.quota": 0, + "mgt_vdom": "root", + "tab_status": "", + "tunnel_ip": "169.254.0.5", + "longitude": "-122.260963", + "patch": 4, + "vm_cpu_limit": 4, + "vm_status": 3, + "lic_region": "", + "hw_rev_major": 0, + "flags": [ + "has_hdd", + "reload" + ], + "sn": "FGVM04TM18000391", + "mr": 0, + "conf_status": "insync", + "os_type": "fos", + "ips_ver": "6.00741(2015-12-01 02:30)", + "db_status": "nomod", + "branch_pt": 231, + "vm_cpu": 1 + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT1" + ], + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.151", + "device_unique_name": "FGT1", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "get" + }, + { + "url": "/dvmdb/adom/ansible/device/FGT2", + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.152", + "device_unique_name": "FGT2", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT2" + ], + "adom": "ansible" + }, + "raw_response": { + "adm_pass": [ + "ENC", + "F27zJSIl5O8O5rlXIi7BzHIUO5d3ZAuNxoniR42zOxGHyqZCx1OyA81b7v6dNwE30nBhjqfD+IDRmSPEW6qxKIQ2UV5eh8zgDNj8i5lj5gTvbLN5A4BR4CMLQo7nYTTomHUJQrGPfYskuxm74JGik+di9TrqOhvpZL8d1zj3XHx5pq+d" + ], + "faz.perm": 0, + "hostname": "ansible-fgt02", + "foslic_type": "temporary", + "mgmt.__data[7]": 0, + "av_ver": "1.00000(2018-04-09 18:07)", + "ip": "10.7.220.152", + "foslic_utm": null, + "logdisk_size": 30235, + "mgmt.__data[6]": 1, + "fsw_cnt": 0, + "app_ver": "", + "ips_ext": 0, + "vm_mem": 1003, + "maxvdom": 10, + "conn_mode": "passive", + "mgt_vdom": "root", + "mgmt.__data[1]": 0, + "hw_rev_major": 0, + "name": "FGT2", + "node_flags": 0, + "foslic_ram": 0, + "mgmt.__data[5]": 0, + "ha_mode": "standalone", + "hw_rev_minor": 0, + "mgmt_if": "port1", + "source": "faz", + "mgmt_id": 1555154046, + "version": 600, + "build": 231, + "latitude": "47.473991", + "foslic_cpu": 0, + "last_resync": 1550634728, + "hdisk_size": 30720, + "adm_usr": "admin", + "vm_lic_expire": 0, + "sn": "FGVM04TM18000392", + "ha_slave": null, + "psk": "", + "foslic_last_sync": 0, + "tunnel_cookie": "", + "vm_mem_limit": 6144, + "mr": 0, + "lic_flags": 0, + "oid": 378, + "conn_status": "up", + "fex_cnt": 0, + "vm_cpu": 1, + "beta": -1, + "ha_group_name": "", + "dev_status": "retrieved", + "platform_str": "FortiGate-VM64", + "last_checked": 1550634728, + "branch_pt": 231, + "faz.used": 0, + "patch": 4, + "fap_cnt": 0, + "foslic_dr_site": "disable", + "mgmt_mode": "fmgfaz", + "vdom": [ + { + "status": null, + "oid": 3, + "name": "root", + "node_flags": 4, + "devid": "FGT2", + "tab_status": null, + "comments": "", + "flags": null, + "opmode": "nat", + "ext_flags": 1, + "rtm_prof_id": 0 + } + ], + "desc": "", + "foslic_inst_time": 0, + "mgmt.__data[0]": 3870643, + "ha_group_id": 0, + "location_from": "GUI(10.0.0.151)", + "faz.quota": 0, + "faz.full_act": 0, + "tab_status": "", + "tunnel_ip": "169.254.0.3", + "longitude": "-122.260963", + "mgmt.__data[4]": 1052262400, + "vm_cpu_limit": 4, + "vm_status": 3, + "lic_region": "", + "mgmt.__data[2]": 0, + "flags": [ + "has_hdd", + "reload" + ], + "opts": 0, + "checksum": "56 e9 a7 14 e2 61 05 f9 ec 2b 00 1e 36 bc af c8", + "conf_status": "insync", + "os_type": "fos", + "ips_ver": "6.00741(2015-12-01 02:30)", + "db_status": "mod", + "mgmt.__data[3]": 0, + "os_ver": "6.0" + }, + "post_method": "get" + }, + { + "url": "/dvmdb/adom/ansible/device/FGT3", + "raw_response": { + "adm_pass": [ + "ENC", + "F27zJSIl5O8O5rlXIi7BzHIUO5d3ZAuNxoniR42zOxGHyqZCx1OyA81b7v6dNwE30nBhjqfD+IDRmSPEW6qxKIQ2UV5eh8zgDNj8i5lj5gTvbLN5A4BR4CMLQo7nYTTomHUJQrGPfYskuxm74JGik+di9TrqOhvpZL8d1zj3XHx5pq+d" + ], + "faz.perm": 0, + "foslic_ram": 0, + "foslic_type": "temporary", + "last_checked": 1550634754, + "psk": "", + "opts": 0, + "ip": "10.7.220.153", + "foslic_utm": null, + "logdisk_size": 30235, + "mgmt.__data[6]": 1, + "foslic_last_sync": 0, + "app_ver": "", + "ips_ext": 0, + "vm_mem": 1003, + "mgmt.__data[4]": 1052262400, + "desc": "", + "maxvdom": 10, + "conn_mode": "passive", + "location_from": "GUI(10.0.0.151)", + "mgmt.__data[1]": 0, + "os_ver": "6.0", + "faz.full_act": 0, + "node_flags": 0, + "hostname": "ansible-fgt03", + "mgmt.__data[5]": 0, + "mgmt_id": 1175062219, + "hw_rev_minor": 0, + "mgmt_if": "port1", + "source": "faz", + "ha_mode": "standalone", + "version": 600, + "build": 231, + "latitude": "47.473991", + "foslic_cpu": 0, + "last_resync": 1550634754, + "hdisk_size": 30720, + "adm_usr": "admin", + "vm_lic_expire": 0, + "conf_status": "insync", + "ha_slave": null, + "av_ver": "1.00000(2018-04-09 18:07)", + "fsw_cnt": 0, + "tunnel_cookie": "", + "foslic_inst_time": 0, + "lic_flags": 0, + "oid": 390, + "conn_status": "up", + "fex_cnt": 0, + "mgmt.__data[3]": 0, + "beta": -1, + "ha_group_name": "", + "dev_status": "retrieved", + "platform_str": "FortiGate-VM64", + "mgmt.__data[7]": 0, + "faz.used": 0, + "fap_cnt": 0, + "foslic_dr_site": "disable", + "mgmt_mode": "fmgfaz", + "vdom": [ + { + "status": null, + "oid": 3, + "name": "root", + "node_flags": 4, + "devid": "FGT3", + "tab_status": null, + "comments": "", + "flags": null, + "opmode": "nat", + "ext_flags": 1, + "rtm_prof_id": 0 + } + ], + "name": "FGT3", + "vm_mem_limit": 6144, + "mgmt.__data[0]": 3870643, + "ha_group_id": 0, + "mgmt.__data[2]": 0, + "faz.quota": 0, + "checksum": "30 fc af f5 58 e4 1e 2d 46 c0 07 4b b6 4b c2 1b", + "tab_status": "", + "tunnel_ip": "169.254.0.4", + "longitude": "-122.260963", + "patch": 4, + "vm_cpu_limit": 4, + "vm_status": 3, + "lic_region": "", + "mgt_vdom": "root", + "flags": [ + "has_hdd", + "reload" + ], + "sn": "FGVM04TM18000393", + "mr": 0, + "hw_rev_major": 0, + "os_type": "fos", + "ips_ver": "6.00741(2015-12-01 02:30)", + "db_status": "mod", + "branch_pt": 231, + "vm_cpu": 1 + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT3" + ], + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.153", + "device_unique_name": "FGT3", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "get" + }, + { + "raw_response": { + "status": { + "message": "Object does not exist", + "code": -3 + }, + "url": "/dvmdb/adom/ansible/device/FGT1" + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT1" + ], + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.151", + "device_unique_name": "FGT1", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "get" + }, + { + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.152", + "device_unique_name": "FGT2", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT2" + ], + "adom": "ansible" + }, + "raw_response": { + "status": { + "message": "Object does not exist", + "code": -3 + }, + "url": "/dvmdb/adom/ansible/device/FGT2" + }, + "post_method": "get" + }, + { + "raw_response": { + "status": { + "message": "Object does not exist", + "code": -3 + }, + "url": "/dvmdb/adom/ansible/device/FGT3" + }, + "datagram_sent": { + "filter": [ + "name", + "==", + "FGT3" + ], + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.153", + "device_unique_name": "FGT3", + "mode": "add", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "get" + } + ], + "delete_device": [ + { + "paramgram_used": { + "device_username": "admin", + "adom": "root", + "device_ip": "10.7.220.151", + "device_unique_name": "FGT1", + "mode": "delete", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "device": "FGT1", + "flags": [ + "create_task", + "nonblocking" + ], + "adom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvm/cmd/del/device/" + }, + "post_method": "exec" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvm/cmd/del/device/" + }, + "datagram_sent": { + "device": "FGT2", + "flags": [ + "create_task", + "nonblocking" + ], + "adom": "ansible" + }, + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.152", + "device_unique_name": "FGT2", + "mode": "delete", + "device_serial": null, + "device_password": "fortinet" + }, + "post_method": "exec" + }, + { + "paramgram_used": { + "device_username": "admin", + "adom": "ansible", + "device_ip": "10.7.220.153", + "device_unique_name": "FGT3", + "mode": "delete", + "device_serial": null, + "device_password": "fortinet" + }, + "datagram_sent": { + "device": "FGT3", + "flags": [ + "create_task", + "nonblocking" + ], + "adom": "ansible" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvm/cmd/del/device/" + }, + "post_method": "exec" + } + ] +} diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json new file mode 100644 index 000000000..fb65ca5da --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json @@ -0,0 +1,2063 @@ +{ + "set_devprof_admin": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": 4433, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": "enable", + "admin_timeout": 60, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_fortianalyzer_target": "10.7.220.38", + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": 8080, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": "blue", + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "ntp_v3": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": "this-fmg", + "dns_primary_ipv4": null, + "admin_language": "english", + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "smtp_replyto": null, + "admin_https_redirect": "enable" + }, + "datagram_sent": { + "admintimeout": 60, + "switch-controller": "enable", + "language": "english", + "admin-port": 8080, + "gui-theme": "blue", + "admin-https-redirect": "enable", + "admin-sport": 4433 + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/global" + }, + "post_method": "set" + } + ], + "set_devprof_snmp_v3": [ + { + "paramgram_used": { + "snmpv3_security_level": "auth-priv", + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": "enable", + "snmpv3_trap_status": "enable", + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": "ansibleSNMPv3", + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": "sha", + "smtp_port": null, + "snmpv3_priv_pwd": "fortinet", + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": 161, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60", + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": "enable", + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": "0.0.0.0", + "snmpv3_trap_rport": 162, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": "aes256", + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": "fortinet", + "smtp_source_ipv4": null, + "snmpv3_status": "enable", + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "ntp_v3": null + }, + "datagram_sent": { + "notify-hosts": [ + "10.7.220.59", + "10.7.220.60" + ], + "name": "ansibleSNMPv3", + "query-port": 161, + "auth-pwd": "fortinet", + "source-ip": "0.0.0.0", + "priv-pwd": "fortinet", + "trap-lport": 162, + "ha-direct": 0, + "trap-rport": 162, + "events": 1647387997183 + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/user" + }, + "post_method": "set" + } + ], + "set_devprof_scope": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": "FGT1,FGT2", + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "ntp_v3": null + }, + "datagram_sent": { + "type": "devprof", + "name": "ansibleTest", + "scope member": [ + { + "name": "FGT1" + }, + { + "name": "FGT2" + } + ], + "description": "CreatedByAnsible" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/devprof/adom/ansible" + }, + "post_method": "set" + } + ], + "set_devprof_snmp": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": "enable", + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "ntp_v3": null + }, + "datagram_sent": { + "status": "enable" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo" + }, + "post_method": "set" + }, + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": "enable", + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": "ansibleV2c", + "syslog_facility": "syslog", + "snmp_v2c_status": "enable", + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": 1, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0", + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": 162, + "snmp_v2c_trap_status": "enable", + "snmp_status": "enable", + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": "10.7.220.41", + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "ntp_auth": null, + "snmp_v2c_trap_port": 161, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255", + "ntp_v3": null + }, + "datagram_sent": { + "status": "enable" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo" + }, + "post_method": "set" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo" + }, + "datagram_sent": { + "status": "enable" + }, + "paramgram_used": { + "snmpv3_security_level": "auth-priv", + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": "enable", + "snmpv3_trap_status": "enable", + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": "ansibleSNMPv3", + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": "sha", + "smtp_port": null, + "snmpv3_priv_pwd": "fortinet", + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": null, + "snmpv3_auth_pwd": "fortinet", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": 161, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60", + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": "enable", + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": "0.0.0.0", + "snmpv3_trap_rport": 162, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": "aes256", + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": "enable", + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_https_redirect": null + }, + "post_method": "set" + } + ], + "set_devprof": [ + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/devprof/adom/ansible/ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "smtp_port": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "ntp_auth": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "delete", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": "ansibleTest", + "ntp_v3": null, + "admin_https_redirect": null + }, + "post_method": "delete" + } + ], + "set_devprof_dns": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": "ansible.local", + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": "4.4.4.4", + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "ntp_v3": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": "8.8.8.8", + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "smtp_replyto": null, + "admin_https_redirect": null + }, + "datagram_sent": { + "domain": "ansible.local", + "primary": "8.8.8.8", + "secondary": "4.4.4.4" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/dns" + }, + "post_method": "set" + } + ], + "set_devprof_syslog": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "kernel", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": 514, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": "10.7.220.59", + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": "enable", + "snmp_v2c_trap_hosts_ipv4": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": "critical", + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "ntp_v3": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "smtp_replyto": null, + "admin_https_redirect": null + }, + "datagram_sent": { + "status": "enable", + "mode": "udp", + "server": "10.7.220.59", + "port": 514, + "facility": "kernel" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/log/syslogd/setting" + }, + "post_method": "set" + } + ], + "set_devprof_snmp_v2c": [ + { + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/community", + "raw_response": { + "id": 1 + }, + "datagram_sent": { + "status": "enable", + "trap-v2c-lport": 162, + "trap-v2c-status": "enable", + "name": "ansibleV2c", + "query-v1-port": 161, + "meta fields": {}, + "query-v1-status": 0, + "trap-v2c-rport": 161, + "trap-v1-rport": 162, + "query-v2c-port": 162, + "hosts": [ + { + "ip": [ + "10.7.220.59", + "255.255.255.255" + ], + "source-ip": "0.0.0.0", + "meta fields": {}, + "ha-direct": "enable", + "id": 1, + "host-type": "query" + }, + { + "ip": [ + "10.7.220.0", + "255.255.255.0" + ], + "source-ip": "0.0.0.0", + "meta fields": {}, + "ha-direct": "enable", + "id": 2, + "host-type": "query" + }, + { + "ip": [ + "10.7.220.59", + "255.255.255.255" + ], + "source-ip": "10.7.220.41", + "meta fields": {}, + "ha-direct": "enable", + "id": 3, + "host-type": "trap" + }, + { + "ip": [ + "10.7.220.60", + "255.255.255.255" + ], + "source-ip": "10.7.220.41", + "meta fields": {}, + "ha-direct": "enable", + "id": 4, + "host-type": "trap" + } + ], + "trap-v1-status": 0, + "events": 411578417151, + "query-v2c-status": "enable", + "id": 1, + "trap-v1-lport": 162 + }, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": "enable", + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": "ansibleV2c", + "syslog_facility": "syslog", + "snmp_v2c_status": "enable", + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": "10.7.220.41", + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": 162, + "snmp_v2c_trap_status": "enable", + "snmp_status": "enable", + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": 1, + "admin_http_port": null, + "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0", + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255", + "provision_targets": null, + "snmp_v2c_trap_port": 161, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "ntp_v3": null, + "admin_https_redirect": null + }, + "post_method": "set" + } + ], + "get_devprof": [ + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": "enable", + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "kernel", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": 514, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": "10.7.220.59", + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": "enable", + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": "critical", + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "snmp_v2c_trap_hosts_ipv4": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "ntp_v3": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": "enable", + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": "ansibleV2c", + "syslog_facility": "syslog", + "snmp_v2c_status": "enable", + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": "10.7.220.41", + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": 162, + "snmp_v2c_trap_status": "enable", + "snmp_status": "enable", + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": 1, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0", + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "provision_targets": null, + "snmp_v2c_trap_port": 161, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255", + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "paramgram_used": { + "snmpv3_security_level": "auth-priv", + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": "enable", + "snmpv3_trap_status": "enable", + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": "ansibleSNMPv3", + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": "sha", + "smtp_port": null, + "snmpv3_priv_pwd": "fortinet", + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": 161, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60", + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": "enable", + "syslog_status": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": "0.0.0.0", + "snmpv3_trap_rport": 162, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "ntp_v3": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": "aes256", + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": "fortinet", + "smtp_source_ipv4": null, + "snmpv3_status": "enable", + "delete_provisioning_template": null, + "smtp_replyto": null, + "admin_https_redirect": null + }, + "datagram_sent": {}, + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": "fortiguard", + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": "enable", + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": 60, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "snmp_v2c_trap_hosts_ipv4": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "ntp_v3": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": "custom", + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": "10.7.220.32,10.7.220.1", + "admin_https_port": null, + "ntp_status": "enable", + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": "enable", + "snmp_v2c_id": null, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": 60, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": "fortinet", + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": 4433, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": 60, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": "10.7.220.38", + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": 8080, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": "blue", + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "snmp_v2c_trap_hosts_ipv4": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": "this-fmg", + "admin_switch_controller": "enable", + "admin_language": "english", + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "ntp_v3": null, + "admin_https_redirect": "enable" + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": "disable", + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": 25, + "snmpv3_priv_pwd": null, + "smtp_server": "10.7.220.32", + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": "ansible", + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": "fortinet", + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": "ansible@do-not-reply.com", + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": "starttls", + "mode": "set", + "smtp_source_ipv4": "0.0.0.0", + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": "ansible.local", + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": "8.8.8.8", + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": "4.4.4.4", + "smtp_replyto": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "snmp_v2c_trap_hosts_ipv4": null, + "provision_targets": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "ntp_v3": null, + "admin_https_redirect": null + }, + "post_method": "get" + }, + { + "url": "/pm/devprof/adom/ansible/ansibleTest", + "raw_response": { + "enabled options": [ + "dns", + "ntp", + "email", + "admin", + "snmp", + "repmsg", + "ftgd", + "log" + ], + "oid": 1542, + "type": "devprof", + "description": "CreatedByAnsible", + "name": "ansibleTest" + }, + "datagram_sent": {}, + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_trap_src_ipv4": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "dns_primary_ipv4": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "dns_secondary_ipv4": null, + "smtp_username": null, + "snmpv3_auth_pwd": null, + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_fortianalyzer_target": null, + "ntp_auth": null, + "snmp_v2c_id": null, + "admin_http_port": null, + "ntp_v3": null, + "snmp_v2c_query_hosts_ipv4": null, + "ntp_sync_interval": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "syslog_filter": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "provision_targets": "FGT1,FGT2", + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "admin_switch_controller": null, + "admin_language": null, + "smtp_conn_sec": null, + "mode": "set", + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_https_redirect": null + }, + "post_method": "get" + } + ], + "set_devprof_ntp": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": "fortiguard", + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": "enable", + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "snmp_v2c_trap_hosts_ipv4": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": 60, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "ntp_v3": null, + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "smtp_replyto": null, + "admin_https_redirect": null + }, + "datagram_sent": { + "ntpsync": 1, + "syncinterval": 60, + "type": 0 + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/ntp" + }, + "post_method": "set" + }, + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": "custom", + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": null, + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": "10.7.220.32,10.7.220.1", + "admin_https_port": null, + "ntp_status": "enable", + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": null, + "snmpv3_priv_pwd": null, + "smtp_server": null, + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": null, + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": null, + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": 60, + "ntp_auth_pwd": "fortinet", + "provisioning_template": "ansibleTest", + "smtp_replyto": null, + "ntp_auth": "enable", + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": null, + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": null, + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "ntp_v3": null + }, + "datagram_sent": { + "ntpsync": 1, + "syncinterval": 60, + "type": 1, + "ntpserver": [ + { + "ntpv3": 0, + "server": "10.7.220.32", + "authentication": 1, + "key": "fortinet", + "id": 1, + "key-id": 1 + }, + { + "ntpv3": 0, + "server": "10.7.220.1", + "authentication": 1, + "key": "fortinet", + "id": 2, + "key-id": 2 + } + ] + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/ntp" + }, + "post_method": "set" + } + ], + "set_devprof_smtp": [ + { + "paramgram_used": { + "snmpv3_security_level": null, + "snmp_v2c_query_status": null, + "provision_targets": null, + "ntp_type": null, + "dns_suffix": null, + "snmpv3_queries": null, + "snmpv3_trap_status": null, + "snmp_v2c_name": null, + "syslog_facility": "syslog", + "snmp_v2c_status": null, + "smtp_validate_cert": "disable", + "snmpv3_name": null, + "snmp_v2c_id": null, + "syslog_port": null, + "ntp_server": null, + "admin_https_port": null, + "ntp_status": null, + "syslog_server": null, + "admin_switch_controller": null, + "admin_timeout": null, + "snmpv3_auth_proto": null, + "smtp_port": 25, + "snmpv3_priv_pwd": null, + "smtp_server": "10.7.220.32", + "syslog_enc_algorithm": "disable", + "snmp_v2c_query_hosts_ipv4": null, + "smtp_username": "ansible", + "mode": "set", + "syslog_certificate": null, + "admin_fortiguard_target": null, + "snmpv3_query_port": null, + "smtp_password": "fortinet", + "adom": "ansible", + "snmpv3_notify_hosts": null, + "syslog_mode": "udp", + "snmp_v2c_query_port": null, + "snmp_v2c_trap_status": null, + "snmp_status": null, + "syslog_status": null, + "admin_https_redirect": null, + "admin_fortianalyzer_target": null, + "snmp_v2c_trap_src_ipv4": null, + "admin_http_port": null, + "dns_secondary_ipv4": null, + "syslog_filter": null, + "snmpv3_source_ip": null, + "snmpv3_trap_rport": null, + "admin_gui_theme": null, + "ntp_sync_interval": null, + "ntp_auth_pwd": null, + "provisioning_template": "ansibleTest", + "smtp_replyto": "ansible@do-not-reply.com", + "ntp_auth": null, + "snmp_v2c_trap_port": null, + "snmpv3_priv_proto": null, + "admin_enable_fortiguard": null, + "dns_primary_ipv4": null, + "admin_language": null, + "smtp_conn_sec": "starttls", + "snmpv3_auth_pwd": null, + "smtp_source_ipv4": "0.0.0.0", + "snmpv3_status": null, + "delete_provisioning_template": null, + "snmp_v2c_trap_hosts_ipv4": null, + "ntp_v3": null + }, + "datagram_sent": { + "username": "ansible", + "authenticate": 1, + "source-ip": "0.0.0.0", + "validate-server": 0, + "server": "10.7.220.32", + "port": 25, + "security": 1, + "password": "fortinet", + "reply-to": "ansible@do-not-reply.com" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/email-server" + }, + "post_method": "set" + } + ] +} diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json new file mode 100644 index 000000000..27c8483a5 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json @@ -0,0 +1,241 @@ +{ + "fmgr_set_ha_peer": [ + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha/peer/" + }, + "datagram_sent": { + "status": "enable", + "ip": "10.7.220.36", + "serial-number": "FMG-VMTM18001882", + "ip6": null, + "id": 1 + }, + "paramgram_used": { + "fmgr_ha_peer_sn": "FMG-VMTM18001882", + "next_peer_id": 2, + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": null, + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_peer_status": "enable", + "fmgr_ha_file_quota": 4096, + "fmgr_ha_cluster_id": 1, + "peer_id": 1, + "fmgr_ha_peer_ipv4": "10.7.220.36", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_mode": null + }, + "post_method": "set" + }, + { + "paramgram_used": { + "fmgr_ha_peer_sn": "FMG-VMTM18001881", + "next_peer_id": 1, + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": "fortinet", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_cluster_id": 2, + "fmgr_ha_file_quota": 4096, + "fmgr_ha_peer_status": "enable", + "peer_id": 1, + "fmgr_ha_peer_ipv4": "10.7.220.35", + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_mode": "slave" + }, + "datagram_sent": { + "status": "enable", + "ip": "10.7.220.35", + "serial-number": "FMG-VMTM18001881", + "ip6": null, + "id": 1 + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha/peer/" + }, + "post_method": "set" + } + ], + "fmgr_get_ha_peer_list": [ + { + "url": "/cli/global/system/ha/peer/", + "paramgram_used": { + "fmgr_ha_peer_sn": "FMG-VMTM18001882", + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": null, + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_peer_status": "enable", + "fmgr_ha_file_quota": 4096, + "fmgr_ha_cluster_id": 1, + "fmgr_ha_peer_ipv4": "10.7.220.36", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_mode": null + }, + "datagram_sent": {}, + "raw_response": [ + { + "status": "enable", + "ip": "10.7.220.140", + "serial-number": "FMG-VM0A17005535", + "ip6": "::", + "id": 1 + } + ], + "post_method": "get" + }, + { + "url": "/cli/global/system/ha/peer/", + "raw_response": [ + { + "status": "enable", + "ip": "10.7.220.35", + "serial-number": "FMG-VMTM18001881", + "ip6": "::", + "id": 1 + } + ], + "datagram_sent": {}, + "paramgram_used": { + "fmgr_ha_peer_sn": "FMG-VMTM18001881", + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": "fortinet", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_cluster_id": 2, + "fmgr_ha_file_quota": 4096, + "fmgr_ha_peer_status": "enable", + "fmgr_ha_peer_ipv4": "10.7.220.35", + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_mode": "slave" + }, + "post_method": "get" + } + ], + "fmgr_set_ha_mode": [ + { + "paramgram_used": { + "fmgr_ha_peer_sn": null, + "fmgr_ha_hb_threshold": 10, + "fmgr_ha_cluster_pw": "fortinet", + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_peer_status": null, + "fmgr_ha_file_quota": 2048, + "fmgr_ha_cluster_id": 2, + "fmgr_ha_peer_ipv4": null, + "fmgr_ha_hb_interval": 15, + "fmgr_ha_mode": "master" + }, + "datagram_sent": { + "file-quota": 2048, + "clusterid": 2, + "hb-lost-threshold": 10, + "mode": "master", + "hb-interval": 15, + "password": "fortinet" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha" + }, + "post_method": "set" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha" + }, + "datagram_sent": { + "file-quota": 4096, + "clusterid": 2, + "hb-lost-threshold": 3, + "mode": "slave", + "hb-interval": 5, + "password": "fortinet" + }, + "paramgram_used": { + "fmgr_ha_peer_sn": null, + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": "fortinet", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_cluster_id": 2, + "fmgr_ha_file_quota": 4096, + "fmgr_ha_peer_status": null, + "fmgr_ha_peer_ipv4": null, + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_mode": "slave" + }, + "post_method": "set" + }, + { + "paramgram_used": { + "fmgr_ha_peer_sn": "FMG-VMTM18001881", + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_cluster_pw": "fortinet", + "fmgr_ha_peer_ipv6": null, + "fmgr_ha_peer_status": "enable", + "fmgr_ha_file_quota": 4096, + "fmgr_ha_cluster_id": 2, + "fmgr_ha_peer_ipv4": "10.7.220.35", + "fmgr_ha_hb_interval": 5, + "fmgr_ha_mode": "slave" + }, + "datagram_sent": { + "file-quota": 4096, + "clusterid": 2, + "hb-lost-threshold": 3, + "mode": "slave", + "hb-interval": 5, + "password": "fortinet" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha" + }, + "post_method": "set" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/cli/global/system/ha" + }, + "datagram_sent": { + "hb-lost-threshold": 3, + "hb-interval": 5, + "clusterid": 1, + "mode": "standalone", + "file-quota": 4096 + }, + "paramgram_used": { + "fmgr_ha_file_quota": 4096, + "fmgr_ha_cluster_pw": null, + "fmgr_ha_peer_sn": null, + "fmgr_ha_hb_interval": 5, + "fmgr_ha_cluster_id": 1, + "fmgr_ha_mode": "standalone", + "fmgr_ha_peer_status": null, + "fmgr_ha_hb_threshold": 3, + "fmgr_ha_peer_ipv4": null, + "fmgr_ha_peer_ipv6": null + }, + "post_method": "set" + } + ] +} diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json new file mode 100644 index 000000000..d75156e1d --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json @@ -0,0 +1,157 @@ +{ + "fmgr_spamfilter_profile_modify": [ + { + "paramgram_used": { + "comment": null, + "smtp": { + "local-override": null, + "hdrip": null, + "log": null, + "tag-type": null, + "tag-msg": null, + "action": null + }, + "spam-log": null, + "gmail": { + "log": null + }, + "spam-bword-table": null, + "mapi": { + "action": null, + "log": null + }, + "flow-based": null, + "spam-mheader-table": null, + "spam-log-fortiguard-response": null, + "yahoo-mail": { + "log": null + }, + "adom": "root", + "pop3": { + "action": null, + "tag-msg": null, + "tag-type": null, + "log": null + }, + "external": null, + "spam-rbl-table": null, + "imap": { + "action": null, + "tag-msg": null, + "tag-type": null, + "log": null + }, + "spam-iptrust-table": null, + "replacemsg-group": null, + "name": "Ansible_Spam_Filter_Profile", + "spam-bwl-table": null, + "spam-filtering": null, + "msn-hotmail": { + "log": null + }, + "spam-bword-threshold": null, + "mode": "delete", + "options": null + }, + "datagram_sent": {}, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/spamfilter/profile/Ansible_Spam_Filter_Profile" + }, + "post_method": "delete" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/spamfilter/profile" + }, + "datagram_sent": { + "comment": "Created by Ansible", + "spam-log-fortiguard-response": "enable", + "spam-log": "enable", + "name": "Ansible_Spam_Filter_Profile", + "spam-filtering": "enable", + "flow-based": "enable", + "spam-bword-threshold": 10, + "external": "enable", + "options": [ + "bannedword", + "spamfsip", + "spamfsurl", + "spamrbl", + "spamfsphish", + "spambwl" + ], + "gmail": { + "log": "enable" + } + }, + "paramgram_used": { + "comment": "Created by Ansible", + "smtp": { + "local-override": null, + "hdrip": null, + "log": null, + "tag-type": null, + "tag-msg": null, + "action": null + }, + "yahoo-mail": { + "log": null + }, + "gmail": { + "log": "enable" + }, + "spam-bword-table": null, + "mapi": { + "action": null, + "log": null + }, + "flow-based": "enable", + "spam-mheader-table": null, + "spam-log-fortiguard-response": "enable", + "spam-log": "enable", + "adom": "root", + "pop3": { + "action": null, + "tag-type": null, + "log": null, + "tag-msg": null + }, + "external": "enable", + "spam-rbl-table": null, + "imap": { + "action": null, + "tag-type": null, + "log": null, + "tag-msg": null + }, + "spam-iptrust-table": null, + "name": "Ansible_Spam_Filter_Profile", + "replacemsg-group": null, + "spam-bwl-table": null, + "spam-filtering": "enable", + "msn-hotmail": { + "log": null + }, + "spam-bword-threshold": 10, + "mode": "set", + "options": [ + "bannedword", + "spamfsip", + "spamfsurl", + "spamrbl", + "spamfsphish", + "spambwl" + ] + }, + "post_method": "set" + } + ] +} diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json new file mode 100644 index 000000000..6dc02883f --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json @@ -0,0 +1,214 @@ +{ + "fmgr_firewall_ssl_ssh_profile_modify": [ + { + "paramgram_used": { + "comment": null, + "untrusted-caname": null, + "mapi-over-https": null, + "whitelist": null, + "caname": null, + "ftps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "client-cert-request": null, + "ports": null, + "untrusted-cert": null + }, + "ssl-exemptions-log": null, + "https": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "client-cert-request": null, + "ports": null, + "untrusted-cert": null + }, + "imaps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "client-cert-request": null, + "ports": null, + "untrusted-cert": null + }, + "server-cert-mode": null, + "adom": "root", + "ssl-exempt": { + "regex": null, + "wildcard-fqdn": null, + "fortiguard-category": null, + "address6": null, + "address": null, + "type": null + }, + "ssl": { + "inspect-all": null, + "allow-invalid-server-cert": null, + "client-cert-request": null, + "untrusted-cert": null, + "unsupported-ssl": null + }, + "ssh": { + "status": null, + "inspect-all": null, + "ssh-tun-policy-check": null, + "ssh-policy-check": null, + "ssh-algorithm": null, + "unsupported-version": null, + "ports": null + }, + "use-ssl-server": null, + "server-cert": null, + "name": "Ansible_SSL_SSH_Profile", + "ssl-anomalies-log": null, + "ssl-server": { + "pop3s-client-cert-request": null, + "imaps-client-cert-request": null, + "smtps-client-cert-request": null, + "ip": null, + "ssl-other-client-cert-request": null, + "https-client-cert-request": null, + "ftps-client-cert-request": null + }, + "smtps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "client-cert-request": null, + "ports": null, + "untrusted-cert": null + }, + "rpc-over-https": null, + "mode": "delete", + "pop3s": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "client-cert-request": null, + "ports": null, + "untrusted-cert": null + } + }, + "datagram_sent": {}, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/firewall/ssl-ssh-profile/Ansible_SSL_SSH_Profile" + }, + "post_method": "delete" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/firewall/ssl-ssh-profile" + }, + "datagram_sent": { + "comment": "Created by Ansible Module TEST", + "server-cert-mode": "replace", + "name": "Ansible_SSL_SSH_Profile", + "ssl-anomalies-log": "enable", + "mapi-over-https": "enable", + "whitelist": "enable", + "ssl-exemptions-log": "enable", + "rpc-over-https": "enable", + "use-ssl-server": "enable" + }, + "paramgram_used": { + "comment": "Created by Ansible Module TEST", + "untrusted-caname": null, + "mapi-over-https": "enable", + "whitelist": "enable", + "caname": null, + "ftps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "untrusted-cert": null, + "client-cert-request": null, + "ports": null + }, + "ssl-exemptions-log": "enable", + "https": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "untrusted-cert": null, + "client-cert-request": null, + "ports": null + }, + "pop3s": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "untrusted-cert": null, + "client-cert-request": null, + "ports": null + }, + "server-cert-mode": "replace", + "adom": "root", + "ssl-exempt": { + "regex": null, + "wildcard-fqdn": null, + "fortiguard-category": null, + "address6": null, + "address": null, + "type": null + }, + "ssl": { + "unsupported-ssl": null, + "inspect-all": null, + "allow-invalid-server-cert": null, + "untrusted-cert": null, + "client-cert-request": null + }, + "ssh": { + "status": null, + "inspect-all": null, + "ssh-tun-policy-check": null, + "ssh-policy-check": null, + "ssh-algorithm": null, + "unsupported-version": null, + "ports": null + }, + "server-cert": null, + "name": "Ansible_SSL_SSH_Profile", + "ssl-anomalies-log": "enable", + "ssl-server": { + "pop3s-client-cert-request": null, + "imaps-client-cert-request": null, + "smtps-client-cert-request": null, + "ip": null, + "ssl-other-client-cert-request": null, + "https-client-cert-request": null, + "ftps-client-cert-request": null + }, + "smtps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "untrusted-cert": null, + "client-cert-request": null, + "ports": null + }, + "imaps": { + "status": null, + "allow-invalid-server-cert": null, + "unsupported-ssl": null, + "untrusted-cert": null, + "client-cert-request": null, + "ports": null + }, + "rpc-over-https": "enable", + "mode": "set", + "use-ssl-server": "enable" + }, + "post_method": "set" + } + ] +} diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py new file mode 100644 index 000000000..b45c6e01a --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py @@ -0,0 +1,64 @@ +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +from ansible_collections.community.fortios.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase + + +class TestFortimanagerModule(ModuleTestCase): + + def execute_module(self, failed=False, changed=False, commands=None, sort=True, defaults=False): + + self.load_fixtures(commands) + + if failed: + result = self.failed() + self.assertTrue(result['failed'], result) + else: + result = self.changed(changed) + self.assertEqual(result['changed'], changed, result) + + if commands is not None: + if sort: + self.assertEqual(sorted(commands), sorted(result['commands']), result['commands']) + else: + self.assertEqual(commands, result['commands'], result['commands']) + + return result + + def failed(self): + with self.assertRaises(AnsibleFailJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertTrue(result['failed'], result) + return result + + def changed(self, changed=False): + with self.assertRaises(AnsibleExitJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertEqual(result['changed'], changed, result) + return result + + def load_fixtures(self, commands=None): + pass diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py new file mode 100644 index 000000000..0d3a3005d --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py @@ -0,0 +1,272 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_device +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_discover_device(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.151 + # device_unique_name: FGT1 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.152 + # device_unique_name: FGT2 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.153 + # device_unique_name: FGT3 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + + # Test using fixture 1 # + output = fmgr_device.discover_device(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_device.discover_device(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 3 # + output = fmgr_device.discover_device(fmg_instance, fixture_data[2]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + + +def test_add_device(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.151 + # device_unique_name: FGT1 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.152 + # device_unique_name: FGT2 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.153 + # device_unique_name: FGT3 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + + # Test using fixture 1 # + output = fmgr_device.add_device(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_device.add_device(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 3 # + output = fmgr_device.add_device(fmg_instance, fixture_data[2]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + + +def test_delete_device(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # device_username: admin + # adom: root + # device_ip: 10.7.220.151 + # device_unique_name: FGT1 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.152 + # device_unique_name: FGT2 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.153 + # device_unique_name: FGT3 + # mode: exec + # device_serial: None + # device_password: fortinet + ################################################## + + # Test using fixture 1 # + output = fmgr_device.delete_device(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device.delete_device(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_device.delete_device(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_get_device(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.151 + # device_unique_name: FGT1 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.152 + # device_unique_name: FGT2 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.153 + # device_unique_name: FGT3 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.151 + # device_unique_name: FGT1 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.152 + # device_unique_name: FGT2 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + ################################################## + # device_username: admin + # adom: ansible + # device_ip: 10.7.220.153 + # device_unique_name: FGT3 + # mode: get + # device_serial: None + # device_password: fortinet + ################################################## + + # Test using fixture 1 # + output = fmgr_device.get_device(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_device.get_device(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 3 # + output = fmgr_device.get_device(fmg_instance, fixture_data[2]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 4 # + output = fmgr_device.get_device(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 5 # + output = fmgr_device.get_device(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 6 # + output = fmgr_device.get_device(fmg_instance, fixture_data[5]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py new file mode 100644 index 000000000..b0540e970 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py @@ -0,0 +1,188 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_device_config +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_config.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_update_device_hostname(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # adom: ansible + # interface: None + # device_unique_name: FGT1 + # install_config: disable + # device_hostname: ansible-fgt01 + # interface_ip: None + # interface_allow_access: None + # mode: update + ################################################## + ################################################## + # adom: ansible + # interface: None + # device_unique_name: FGT2 + # install_config: disable + # device_hostname: ansible-fgt02 + # interface_ip: None + # interface_allow_access: None + # mode: update + ################################################## + ################################################## + # adom: ansible + # interface: None + # device_unique_name: FGT3 + # install_config: disable + # device_hostname: ansible-fgt03 + # interface_ip: None + # interface_allow_access: None + # mode: update + ################################################## + + # Test using fixture 1 # + output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_update_device_interface(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # adom: ansible + # install_config: disable + # device_unique_name: FGT1 + # interface: port2 + # device_hostname: None + # interface_ip: 10.1.1.1/24 + # interface_allow_access: ping, telnet, https, http + # mode: update + ################################################## + ################################################## + # adom: ansible + # install_config: disable + # device_unique_name: FGT2 + # interface: port2 + # device_hostname: None + # interface_ip: 10.1.2.1/24 + # interface_allow_access: ping, telnet, https, http + # mode: update + ################################################## + ################################################## + # adom: ansible + # install_config: disable + # device_unique_name: FGT3 + # interface: port2 + # device_hostname: None + # interface_ip: 10.1.3.1/24 + # interface_allow_access: ping, telnet, https, http + # mode: update + ################################################## + + # Test using fixture 1 # + output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_exec_config(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # adom: ansible + # interface: None + # device_unique_name: FGT1 + # install_config: enable + # device_hostname: None + # interface_ip: None + # interface_allow_access: None + # mode: exec + ################################################## + ################################################## + # adom: ansible + # install_config: enable + # device_unique_name: FGT2, FGT3 + # interface: None + # device_hostname: None + # interface_ip: None + # interface_allow_access: None + # mode: exec + ################################################## + + # Test using fixture 1 # + output = fmgr_device_config.exec_config(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_device_config.exec_config(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py new file mode 100644 index 000000000..723c29b11 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py @@ -0,0 +1,202 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_device_group +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_group.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_add_device_group(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # mode: add + # grp_name: TestGroup + # vdom: root + ################################################## + ################################################## + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # mode: add + # grp_name: testtest + # vdom: root + ################################################## + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT1 + # mode: add + # grp_name: TestGroup + # vdom: root + ################################################## + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # mode: add + # grp_name: testtest + # vdom: root + ################################################## + + # Test using fixture 1 # + output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -2 + # Test using fixture 2 # + output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == -2 + # Test using fixture 4 # + output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == -2 + + +def test_delete_device_group(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # mode: delete + # grp_name: TestGroup + # vdom: root + ################################################## + ################################################## + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # mode: delete + # grp_name: testtest + # vdom: root + ################################################## + + # Test using fixture 1 # + output = fmgr_device_group.delete_device_group(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_group.delete_device_group(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_add_group_member(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT1 + # mode: add + # grp_name: TestGroup + # vdom: root + ################################################## + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # mode: add + # grp_name: testtest + # vdom: root + ################################################## + + # Test using fixture 1 # + output = fmgr_device_group.add_group_member(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_group.add_group_member(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_delete_group_member(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # mode: delete + # grp_name: testtest + # vdom: root + ################################################## + ################################################## + # grp_desc: None + # adom: ansible + # grp_members: FGT1 + # mode: delete + # grp_name: TestGroup + # vdom: root + ################################################## + + # Test using fixture 1 # + output = fmgr_device_group.delete_group_member(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_group.delete_group_member(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py new file mode 100644 index 000000000..3ece0f222 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py @@ -0,0 +1,1758 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_device_provision_template +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_provision_template.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_get_devprof(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: enable + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: kernel + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: 514 + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: 10.7.220.59 + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: enable + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: critical + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # snmp_v2c_trap_hosts_ipv4: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # ntp_v3: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: enable + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: ansibleV2c + # syslog_facility: syslog + # snmp_v2c_status: enable + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: 10.7.220.41 + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: 162 + # snmp_v2c_trap_status: enable + # snmp_status: enable + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: 1 + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0 + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # provision_targets: None + # snmp_v2c_trap_port: 161 + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255 + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: auth-priv + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: enable + # snmpv3_trap_status: enable + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: ansibleSNMPv3 + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: sha + # smtp_port: None + # snmpv3_priv_pwd: fortinet + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: get + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: 161 + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60 + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: enable + # syslog_status: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: 0.0.0.0 + # snmpv3_trap_rport: 162 + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # ntp_v3: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: aes256 + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: fortinet + # smtp_source_ipv4: None + # snmpv3_status: enable + # delete_provisioning_template: None + # smtp_replyto: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: fortiguard + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: enable + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: 60 + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # snmp_v2c_trap_hosts_ipv4: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # ntp_v3: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: custom + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: 10.7.220.32,10.7.220.1 + # admin_https_port: None + # ntp_status: enable + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: enable + # snmp_v2c_id: None + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: 60 + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: fortinet + # provisioning_template: ansibleTest + # smtp_replyto: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: 4433 + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: 60 + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: 10.7.220.38 + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: 8080 + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: blue + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # snmp_v2c_trap_hosts_ipv4: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: this-fmg + # admin_switch_controller: enable + # admin_language: english + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # ntp_v3: None + # admin_https_redirect: enable + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: disable + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: 25 + # snmpv3_priv_pwd: None + # smtp_server: 10.7.220.32 + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: ansible + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: fortinet + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: ansible@do-not-reply.com + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: starttls + # mode: get + # smtp_source_ipv4: 0.0.0.0 + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: ansible.local + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: 8.8.8.8 + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: 4.4.4.4 + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # snmp_v2c_trap_hosts_ipv4: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # ntp_v3: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # provision_targets: FGT1,FGT2 + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: get + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 3 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[2]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 4 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[3]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 5 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[4]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 6 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[5]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 7 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[6]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 8 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[7]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 9 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[8]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 10 # + output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[9]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + + +def test_set_devprof(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # smtp_port: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # ntp_auth: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_fortianalyzer_target: None + # snmp_v2c_id: None + # admin_http_port: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: delete + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: ansibleTest + # ntp_v3: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_scope(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: FGT1,FGT2 + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # ntp_v3: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_scope(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_snmp(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: enable + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # ntp_v3: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: enable + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: ansibleV2c + # syslog_facility: syslog + # snmp_v2c_status: enable + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: 1 + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0 + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: 162 + # snmp_v2c_trap_status: enable + # snmp_status: enable + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: 10.7.220.41 + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # ntp_auth: None + # snmp_v2c_trap_port: 161 + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255 + # ntp_v3: None + ################################################## + ################################################## + # snmpv3_security_level: auth-priv + # snmp_v2c_query_status: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: enable + # snmpv3_trap_status: enable + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: ansibleSNMPv3 + # snmp_v2c_trap_src_ipv4: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: sha + # smtp_port: None + # snmpv3_priv_pwd: fortinet + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_username: None + # snmpv3_auth_pwd: fortinet + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: 161 + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60 + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: enable + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: None + # admin_http_port: None + # ntp_v3: None + # snmp_v2c_query_hosts_ipv4: None + # ntp_sync_interval: None + # snmpv3_source_ip: 0.0.0.0 + # snmpv3_trap_rport: 162 + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # provision_targets: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: aes256 + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: set + # smtp_source_ipv4: None + # snmpv3_status: enable + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_snmp_v2c(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: enable + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: ansibleV2c + # syslog_facility: syslog + # snmp_v2c_status: enable + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_trap_src_ipv4: 10.7.220.41 + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # dns_primary_ipv4: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # dns_secondary_ipv4: None + # smtp_replyto: None + # smtp_username: None + # snmpv3_auth_pwd: None + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: 162 + # snmp_v2c_trap_status: enable + # snmp_status: enable + # syslog_status: None + # admin_fortianalyzer_target: None + # ntp_auth: None + # snmp_v2c_id: 1 + # admin_http_port: None + # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0 + # ntp_sync_interval: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # syslog_filter: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255 + # provision_targets: None + # snmp_v2c_trap_port: 161 + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # admin_switch_controller: None + # admin_language: None + # smtp_conn_sec: None + # mode: set + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # ntp_v3: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_snmp_v2c(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + + +def test_set_devprof_snmp_v3(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: auth-priv + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: enable + # snmpv3_trap_status: enable + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: ansibleSNMPv3 + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: sha + # smtp_port: None + # snmpv3_priv_pwd: fortinet + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: 161 + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60 + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: enable + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: 0.0.0.0 + # snmpv3_trap_rport: 162 + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: aes256 + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: fortinet + # smtp_source_ipv4: None + # snmpv3_status: enable + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # ntp_v3: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_snmp_v3(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_syslog(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: kernel + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: 514 + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: 10.7.220.59 + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: enable + # snmp_v2c_trap_hosts_ipv4: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: critical + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # ntp_v3: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # smtp_replyto: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_syslog(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_ntp(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: fortiguard + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: enable + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: 60 + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # ntp_v3: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # smtp_replyto: None + # admin_https_redirect: None + ################################################## + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: custom + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: 10.7.220.32,10.7.220.1 + # admin_https_port: None + # ntp_status: enable + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: 60 + # ntp_auth_pwd: fortinet + # provisioning_template: ansibleTest + # smtp_replyto: None + # ntp_auth: enable + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # ntp_v3: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_ntp(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_device_provision_template.set_devprof_ntp(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_admin(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: 4433 + # ntp_status: None + # syslog_server: None + # admin_switch_controller: enable + # admin_timeout: 60 + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_fortianalyzer_target: 10.7.220.38 + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: 8080 + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: blue + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # ntp_v3: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: this-fmg + # dns_primary_ipv4: None + # admin_language: english + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # smtp_replyto: None + # admin_https_redirect: enable + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_admin(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_smtp(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: None + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: disable + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: 25 + # snmpv3_priv_pwd: None + # smtp_server: 10.7.220.32 + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: ansible + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: fortinet + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # admin_https_redirect: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: None + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # smtp_replyto: ansible@do-not-reply.com + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: None + # admin_language: None + # smtp_conn_sec: starttls + # snmpv3_auth_pwd: None + # smtp_source_ipv4: 0.0.0.0 + # snmpv3_status: None + # delete_provisioning_template: None + # snmp_v2c_trap_hosts_ipv4: None + # ntp_v3: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_smtp(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_set_devprof_dns(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # snmpv3_security_level: None + # snmp_v2c_query_status: None + # provision_targets: None + # ntp_type: None + # dns_suffix: ansible.local + # snmpv3_queries: None + # snmpv3_trap_status: None + # snmp_v2c_name: None + # syslog_facility: syslog + # snmp_v2c_status: None + # smtp_validate_cert: None + # snmpv3_name: None + # snmp_v2c_id: None + # syslog_port: None + # ntp_server: None + # admin_https_port: None + # ntp_status: None + # syslog_server: None + # admin_switch_controller: None + # admin_timeout: None + # snmpv3_auth_proto: None + # smtp_port: None + # snmpv3_priv_pwd: None + # smtp_server: None + # syslog_enc_algorithm: disable + # snmp_v2c_query_hosts_ipv4: None + # smtp_username: None + # mode: set + # syslog_certificate: None + # admin_fortiguard_target: None + # snmpv3_query_port: None + # smtp_password: None + # adom: ansible + # snmpv3_notify_hosts: None + # syslog_mode: udp + # snmp_v2c_query_port: None + # snmp_v2c_trap_status: None + # snmp_status: None + # syslog_status: None + # snmp_v2c_trap_hosts_ipv4: None + # admin_fortianalyzer_target: None + # snmp_v2c_trap_src_ipv4: None + # admin_http_port: None + # dns_secondary_ipv4: 4.4.4.4 + # syslog_filter: None + # snmpv3_source_ip: None + # snmpv3_trap_rport: None + # admin_gui_theme: None + # ntp_sync_interval: None + # ntp_auth_pwd: None + # provisioning_template: ansibleTest + # ntp_v3: None + # ntp_auth: None + # snmp_v2c_trap_port: None + # snmpv3_priv_proto: None + # admin_enable_fortiguard: None + # dns_primary_ipv4: 8.8.8.8 + # admin_language: None + # smtp_conn_sec: None + # snmpv3_auth_pwd: None + # smtp_source_ipv4: None + # snmpv3_status: None + # delete_provisioning_template: None + # smtp_replyto: None + # admin_https_redirect: None + ################################################## + + # Test using fixture 1 # + output = fmgr_device_provision_template.set_devprof_dns(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py new file mode 100644 index 000000000..97d4a3f00 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py @@ -0,0 +1,156 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_address +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_address.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_fwobj_ipv4(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 2 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 5 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 6 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[5]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 7 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[6]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 8 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[7]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 9 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[8]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 10 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[9]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 11 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[10]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 12 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[11]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 13 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[12]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 14 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[13]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 15 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[14]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 16 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[15]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 17 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[16]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 18 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[17]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_fmgr_fwobj_ipv6(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 2 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 3 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 5 # + output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == -10131 + + +def test_fmgr_fwobj_multicast(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py new file mode 100644 index 000000000..399fc4c8d --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py @@ -0,0 +1,90 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_ippool +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_ippool.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_fwobj_ippool_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 5 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 6 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[5]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 7 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[6]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 8 # + output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[7]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py new file mode 100644 index 000000000..04877ff5d --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_ippool6 +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_ippool6.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_fwobj_ippool6_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_ippool6.fmgr_fwobj_ippool6_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwobj_ippool6.fmgr_fwobj_ippool6_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py new file mode 100644 index 000000000..57edff901 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py @@ -0,0 +1,123 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_service +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_service.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_fwobj_service_custom(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 5 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 6 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[5]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 7 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[6]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 8 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[7]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 9 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[8]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 10 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[9]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 11 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[10]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 12 # + output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[11]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_fmgr_fwobj_service_group(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_service.fmgr_fwobj_service_group(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 2 # + output = fmgr_fwobj_service.fmgr_fwobj_service_group(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == -10131 + + +def test_fmgr_fwobj_service_category(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwobj_service.fmgr_fwobj_service_category(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -2 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py new file mode 100644 index 000000000..c8dbfc775 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py @@ -0,0 +1,785 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_vip +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_vip.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_firewall_vip_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # comment: Created by Ansible + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # mapped-addr: None + # ssl-client-session-state-timeout: None + # src-filter: None + # server-type: None + # ssl-hpkp-include-subdomains: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: 10.7.220.25 + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: tcp + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # ssl-client-renegotiation: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # weblogic-server: None + # http-cookie-share: None + # color: 17 + # ssl-mode: None + # portforward: enable + # http-multiplex: None + # http-cookie-generation: None + # ssl-client-fallback: None + # extip: 82.72.192.185 + # extintf: any + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + + # adom: ansible + # ssl-client-session-state-max: None + # http-ip-header: None + # http-ip-header-name: None + # ssl-certificate: None + # ssl-hsts: None + # arp-reply: None + # ssl-hsts-include-subdomains: None + # ssl-min-version: None + # ldb-method: None + # ssl-server-session-state-timeout: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: 443 + # name: Basic PNAT Map Port 10443 + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # outlook-web-access: None + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-server-max-version: None + # ssl-hpkp-report-uri: None + # http-cookie-domain-from-host: None + # ssl-algorithm: None + # gratuitous-arp-interval: None + # extport: 10443 + # max-embryonic-connections: None + # mode: set + # http-cookie-path: None + # ssl-pfs: None + # ssl-server-algorithm: None + ################################################## + ################################################## + # comment: Created by Ansible + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # ssl-hsts-include-subdomains: None + # mapped-addr: None + # src-filter: None + # server-type: None + # mode: set + # ssl-hpkp-include-subdomains: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: 3.3.3.0/24, 4.0.0.0/24 + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # ssl-client-renegotiation: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # adom: ansible + # http-cookie-share: None + # ssl-server-session-state-timeout: None + # color: 12 + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # max-embryonic-connections: None + # ssl-client-fallback: None + # ssl-hpkp-report-uri: None + # extip: 192.168.0.1-192.168.0.100 + # extintf: dmz + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + # http-ip-header-name: None + # weblogic-server: None + # ssl-client-session-state-max: None + # http-ip-header: None + + # ssl-hsts: None + # arp-reply: None + # extaddr: None + # ssl-min-version: None + # ldb-method: None + # ssl-certificate: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # outlook-web-access: None + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # name: Basic DNS Translation + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-pfs: None + # ssl-server-max-version: None + # ssl-client-session-state-timeout: None + # http-cookie-domain-from-host: None + # extport: None + # ssl-server-algorithm: None + # gratuitous-arp-interval: None + # http-cookie-path: None + # ssl-algorithm: None + # http-multiplex: None + ################################################## + ################################################## + # comment: Created by Ansible + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # mapped-addr: google-play + # ssl-client-session-state-timeout: None + # src-filter: None + # ldb-method: None + # server-type: None + # ssl-hpkp-include-subdomains: None + # ssl-client-renegotiation: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: None + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # weblogic-server: None + # http-cookie-share: None + # color: 5 + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # ssl-client-fallback: None + # extip: None + # extintf: None + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + + # adom: ansible + # ssl-client-session-state-max: None + # http-ip-header: None + # http-ip-header-name: None + # ssl-certificate: None + # ssl-hsts: None + # arp-reply: None + # extport: None + # ssl-min-version: None + # ssl-server-algorithm: None + # ssl-server-session-state-timeout: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # name: Basic FQDN Translation + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # outlook-web-access: None + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-server-max-version: None + # ssl-hpkp-report-uri: None + # http-cookie-domain-from-host: None + # ssl-algorithm: None + # gratuitous-arp-interval: None + # ssl-hsts-include-subdomains: None + # max-embryonic-connections: None + # mode: set + # http-cookie-path: None + # ssl-pfs: None + # http-multiplex: None + ################################################## + ################################################## + # comment: Created by Ansible + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # mapped-addr: None + # src-filter: None + # server-type: None + # mode: set + # ssl-hpkp-include-subdomains: None + # extport: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: 10.7.220.25 + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # ssl-server-algorithm: None + # extaddr: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # adom: ansible + # http-cookie-share: None + # ssl-server-session-state-timeout: None + # color: 17 + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # max-embryonic-connections: None + # ssl-client-fallback: None + # ssl-hpkp-report-uri: None + # extip: 82.72.192.185 + # extintf: any + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + # http-ip-header-name: None + # weblogic-server: None + # ssl-client-session-state-max: None + # http-ip-header: None + + # ssl-hsts: None + # arp-reply: None + # ssl-client-renegotiation: None + # ssl-min-version: None + # ldb-method: None + # ssl-certificate: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # outlook-web-access: None + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # name: Basic StaticNAT Map + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-pfs: None + # ssl-client-session-state-timeout: None + # http-cookie-domain-from-host: None + # ssl-hsts-include-subdomains: None + # ssl-server-max-version: None + # gratuitous-arp-interval: None + # http-cookie-path: None + # ssl-algorithm: None + # http-multiplex: None + ################################################## + ################################################## + # comment: Created by Ansible + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # mapped-addr: None + # ssl-client-session-state-timeout: None + # src-filter: None + # server-type: None + # ssl-hpkp-include-subdomains: None + # ssl-client-renegotiation: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: 10.7.220.25 + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: tcp + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # weblogic-server: None + # http-cookie-share: None + # color: 17 + # ssl-mode: None + # portforward: enable + # http-cookie-generation: None + # ssl-client-fallback: None + # extip: 82.72.192.185 + # extintf: any + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + + # adom: ansible + # ssl-client-session-state-max: None + # http-ip-header: None + # http-ip-header-name: None + # ssl-min-version: None + # ssl-certificate: None + # ssl-hsts: None + # arp-reply: None + # ssl-hsts-include-subdomains: None + # http-multiplex: None + # ldb-method: None + # ssl-server-session-state-timeout: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: 443 + # name: Basic PNAT Map Port 10443 + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # outlook-web-access: None + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-server-max-version: None + # ssl-hpkp-report-uri: None + # http-cookie-domain-from-host: None + # ssl-algorithm: None + # gratuitous-arp-interval: None + # extport: 10443 + # max-embryonic-connections: None + # mode: set + # http-cookie-path: None + # ssl-pfs: None + # ssl-server-algorithm: None + ################################################## + ################################################## + # comment: None + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # ssl-hpkp: None + # ssl-hsts-include-subdomains: None + # mapped-addr: None + # src-filter: None + # server-type: None + # mode: delete + # ssl-hpkp-include-subdomains: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # mappedip: None + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # adom: ansible + # http-cookie-share: None + # ssl-server-session-state-timeout: None + # color: None + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # max-embryonic-connections: None + # ssl-client-fallback: None + # ssl-hpkp-report-uri: None + # extip: None + # extintf: None + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + # http-ip-header-name: None + # weblogic-server: None + # ssl-client-session-state-max: None + # http-ip-header: None + + # ssl-hsts: None + # arp-reply: None + # ssl-client-renegotiation: None + # http-multiplex: None + # ldb-method: None + # ssl-certificate: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # outlook-web-access: None + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # name: Basic PNAT Map Port 10443 + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-pfs: None + # ssl-server-max-version: None + # ssl-client-session-state-timeout: None + # http-cookie-domain-from-host: None + # extport: None + # ssl-server-algorithm: None + # gratuitous-arp-interval: None + # http-cookie-path: None + # ssl-algorithm: None + # ssl-min-version: None + ################################################## + ################################################## + # comment: None + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # mappedip: None + # mapped-addr: None + # ssl-client-session-state-timeout: None + # src-filter: None + # ldb-method: None + # server-type: None + # ssl-hpkp-include-subdomains: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # ssl-hpkp: None + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # ssl-client-renegotiation: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # weblogic-server: None + # http-cookie-share: None + # color: None + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # ssl-client-fallback: None + # extip: None + # extintf: None + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + + # adom: ansible + # ssl-client-session-state-max: None + # http-ip-header: None + # http-ip-header-name: None + # ssl-certificate: None + # ssl-hsts: None + # arp-reply: None + # extport: None + # http-multiplex: None + # ssl-server-algorithm: None + # ssl-server-session-state-timeout: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # name: Basic StaticNAT Map + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-hpkp-primary: None + # outlook-web-access: None + # ssl-server-session-state-type: None + # ssl-client-session-state-type: None + + # ssl-http-match-host: None + + # ssl-server-max-version: None + # ssl-hpkp-report-uri: None + # http-cookie-domain-from-host: None + # ssl-algorithm: None + # gratuitous-arp-interval: None + # ssl-hsts-include-subdomains: None + # max-embryonic-connections: None + # mode: delete + # http-cookie-path: None + # ssl-pfs: None + # ssl-min-version: None + ################################################## + ################################################## + # comment: None + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # mappedip: None + # mapped-addr: None + # src-filter: None + # server-type: None + # mode: delete + # ssl-hpkp-include-subdomains: None + # extport: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # ssl-hpkp: None + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # ssl-server-algorithm: None + # ssl-client-renegotiation: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # adom: ansible + # http-cookie-share: None + # ssl-server-session-state-timeout: None + # color: None + # ssl-mode: None + # portforward: None + # http-multiplex: None + # http-cookie-generation: None + # max-embryonic-connections: None + # ssl-client-fallback: None + # ssl-hpkp-report-uri: None + # extip: None + # extintf: None + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + # http-ip-header-name: None + # weblogic-server: None + # ssl-client-session-state-max: None + # http-ip-header: None + # ssl-hsts: None + # arp-reply: None + # extaddr: None + # ssl-hpkp-primary: None + # ldb-method: None + # ssl-certificate: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # outlook-web-access: None + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-client-session-state-type: None + # name: Basic DNS Translation + # ssl-server-session-state-type: None + + # ssl-http-match-host: None + # ssl-pfs: None + # ssl-client-session-state-timeout: None + # http-cookie-domain-from-host: None + # ssl-hsts-include-subdomains: None + # ssl-server-max-version: None + # gratuitous-arp-interval: None + # http-cookie-path: None + # ssl-algorithm: None + # ssl-min-version: None + ################################################## + ################################################## + # ldb-method: None + # ssl-send-empty-frags: None + # srcintf-filter: None + # ssl-max-version: None + # ssl-server-session-state-max: None + # mappedip: None + # ssl-hsts: None + # mapped-addr: None + # src-filter: None + # server-type: None + # ssl-hpkp-include-subdomains: None + # ssl-client-renegotiation: None + # ssl-http-location-conversion: None + # https-cookie-secure: None + # extip: None + # ssl-hpkp: None + # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None} + # protocol: None + # ssl-hpkp-backup: None + # ssl-dh-bits: None + # dns-mapping-ttl: None + # ssl-hsts-age: None + # extaddr: None + # ssl-hpkp-primary: None + # monitor: None + # service: None + # ssl-hpkp-age: None + # http-cookie-age: None + # weblogic-server: None + # http-cookie-share: None + # name: Basic FQDN Translation + # color: None + # ssl-mode: None + # portforward: None + # http-cookie-generation: None + # ssl-client-fallback: None + + # http-ip-header: None + # persistence: None + # websphere-server: None + # nat-source-vip: None + # portmapping-type: None + # adom: ansible + # ssl-client-session-state-max: None + # extintf: None + # ssl-server-max-version: None + # http-ip-header-name: None + # ssl-certificate: None + # ssl-server-session-state-type: None + # arp-reply: None + # ssl-hsts-include-subdomains: None + # ssl-min-version: None + # ssl-server-algorithm: None + # ssl-server-session-state-timeout: None + # ssl-server-min-version: None + # http-cookie-domain: None + # mappedport: None + # outlook-web-access: None + # ssl-cipher-suites: {'cipher': None, 'versions': None} + # ssl-client-session-state-type: None + # ssl-http-match-host: None + + # ssl-client-session-state-timeout: None + # comment: None + # ssl-hpkp-report-uri: None + # http-cookie-domain-from-host: None + # ssl-algorithm: None + # gratuitous-arp-interval: None + # extport: None + # max-embryonic-connections: None + # mode: delete + # http-cookie-path: None + # ssl-pfs: None + # http-multiplex: None + ################################################## + + # Test using fixture 1 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == -10131 + # Test using fixture 3 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 5 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[4]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 6 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[5]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 7 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[6]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 8 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[7]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 9 # + output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[8]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py new file mode 100644 index 000000000..767573e22 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py @@ -0,0 +1,596 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwpol_ipv4 +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwpol_ipv4.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_firewall_policy_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # wanopt-passive-opt: None + # package_name: default + # wanopt-detection: None + # scan-botnet-connections: None + # profile-group: None + # wanopt-peer: None + # dscp-match: None + # replacemsg-override-group: None + # internet-service-negate: None + # np-acceleration: None + # learning-mode: None + # session-ttl: None + # ntlm-guest: None + # ips-sensor: None + # diffservcode-rev: None + # match-vip: None + # natip: None + # dlp-sensor: None + # traffic-shaper: None + # groups: None + # schedule-timeout: None + # name: Basic_IPv4_Policy + # tcp-session-without-syn: None + # ntlm: None + # permit-stun-host: None + # diffservcode-forward: None + # internet-service-src-custom: None + # mode: set + # disclaimer: None + # rtp-nat: None + # auth-cert: None + # timeout-send-rst: None + # auth-redirect-addr: None + # ssl-mirror-intf: None + # identity-based-route: None + # natoutbound: None + # wanopt-profile: None + # per-ip-shaper: None + # profile-protocol-options: None + # diffserv-forward: None + # poolname: None + # comments: Created by Ansible + # label: None + # global-label: None + # firewall-session-dirty: None + # wanopt: None + # schedule: always + # internet-service-id: None + # auth-path: None + # vlan-cos-fwd: None + # custom-log-fields: None + # dstintf: any + # srcintf: any + # block-notification: None + # internet-service-src-id: None + # redirect-url: None + # waf-profile: None + # ntlm-enabled-browsers: None + # dscp-negate: None + # action: accept + # fsso-agent-for-ntlm: None + # logtraffic: utm + # vlan-filter: None + # policyid: None + # logtraffic-start: None + # webcache-https: None + # webfilter-profile: None + # internet-service-src: None + # webcache: None + # utm-status: None + # vpn_src_node: {'subnet': None, 'host': None, 'seq': None} + # ippool: None + # service: ALL + # wccp: None + # auto-asic-offload: None + # dscp-value: None + # url-category: None + # capture-packet: None + # adom: ansible + # inbound: None + # internet-service: None + # profile-type: None + # ssl-mirror: None + # srcaddr-negate: None + # gtp-profile: None + # mms-profile: None + # send-deny-packet: None + # devices: None + # permit-any-host: None + # av-profile: None + # internet-service-src-negate: None + # service-negate: None + # rsso: None + # app-group: None + # tcp-mss-sender: None + # natinbound: None + # fixedport: None + # ssl-ssh-profile: None + # outbound: None + # spamfilter-profile: None + # application-list: None + # application: None + # dnsfilter-profile: None + # nat: None + # fsso: None + # vlan-cos-rev: None + # status: None + # dsri: None + # users: None + # voip-profile: None + # dstaddr-negate: None + # traffic-shaper-reverse: None + # internet-service-custom: None + # diffserv-reverse: None + # srcaddr: all + # ssh-filter-profile: None + # delay-tcp-npu-session: None + # icap-profile: None + # captive-portal-exempt: None + # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None} + # app-category: None + # rtp-addr: None + # wsso: None + # tcp-mss-receiver: None + # dstaddr: all + # radius-mac-auth-bypass: None + # vpntunnel: None + ################################################## + ################################################## + # package_name: default + # wanopt-detection: None + # scan-botnet-connections: None + # profile-group: None + # dlp-sensor: None + # dscp-match: None + # replacemsg-override-group: None + # internet-service-negate: None + # np-acceleration: None + # learning-mode: None + # session-ttl: None + # ntlm-guest: None + # ips-sensor: None + # diffservcode-rev: None + # match-vip: None + # natip: None + # wanopt-peer: None + # traffic-shaper: None + # groups: None + # schedule-timeout: None + # name: Basic_IPv4_Policy_2 + # tcp-session-without-syn: None + # rtp-nat: None + # permit-stun-host: None + # natoutbound: None + # internet-service-src-custom: None + # mode: set + # logtraffic: utm + # ntlm: None + # auth-cert: None + # timeout-send-rst: None + # auth-redirect-addr: None + # ssl-mirror-intf: None + # identity-based-route: None + # diffservcode-forward: None + # wanopt-profile: None + # per-ip-shaper: None + # users: None + # diffserv-forward: None + # poolname: None + # comments: Created by Ansible + # label: None + # global-label: None + # firewall-session-dirty: None + # wanopt: None + # schedule: always + # internet-service-id: None + # auth-path: None + # vlan-cos-fwd: None + # custom-log-fields: None + # dstintf: any + # srcintf: any + # block-notification: None + # internet-service-src-id: None + # redirect-url: None + # waf-profile: None + # ntlm-enabled-browsers: None + # dscp-negate: None + # action: accept + # fsso-agent-for-ntlm: None + # disclaimer: None + # vlan-filter: None + # dstaddr-negate: None + # logtraffic-start: None + # webcache-https: None + # webfilter-profile: None + # internet-service-src: None + # webcache: None + # utm-status: None + # vpn_src_node: {'subnet': None, 'host': None, 'seq': None} + # ippool: None + # service: HTTP, HTTPS + # wccp: None + # auto-asic-offload: None + # dscp-value: None + # url-category: None + # capture-packet: None + # adom: ansible + # inbound: None + # internet-service: None + # profile-type: None + # ssl-mirror: None + # srcaddr-negate: None + # gtp-profile: None + # mms-profile: None + # send-deny-packet: None + # devices: None + # permit-any-host: None + # av-profile: None + # internet-service-src-negate: None + # service-negate: None + # rsso: None + # application-list: None + # app-group: None + # tcp-mss-sender: None + # natinbound: None + # fixedport: None + # ssl-ssh-profile: None + # outbound: None + # spamfilter-profile: None + # wanopt-passive-opt: None + # application: None + # dnsfilter-profile: None + # nat: enable + # fsso: None + # vlan-cos-rev: None + # status: None + # dsri: None + # profile-protocol-options: None + # voip-profile: None + # policyid: None + # traffic-shaper-reverse: None + # internet-service-custom: None + # diffserv-reverse: None + # srcaddr: all + # dstaddr: google-play + # delay-tcp-npu-session: None + # icap-profile: None + # captive-portal-exempt: None + # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None} + # app-category: None + # rtp-addr: None + # wsso: None + # tcp-mss-receiver: None + # ssh-filter-profile: None + # radius-mac-auth-bypass: None + # vpntunnel: None + ################################################## + ################################################## + # wanopt-passive-opt: None + # package_name: default + # wanopt-detection: None + # scan-botnet-connections: None + # profile-group: None + # wanopt-peer: None + # dscp-match: None + # replacemsg-override-group: None + # internet-service-negate: None + # np-acceleration: None + # learning-mode: None + # session-ttl: None + # ntlm-guest: None + # ips-sensor: None + # diffservcode-rev: None + # match-vip: None + # natip: None + # dlp-sensor: None + # traffic-shaper: None + # groups: None + # schedule-timeout: None + # name: Basic_IPv4_Policy + # tcp-session-without-syn: None + # ntlm: None + # permit-stun-host: None + # diffservcode-forward: None + # internet-service-src-custom: None + # mode: delete + # disclaimer: None + # rtp-nat: None + # auth-cert: None + # timeout-send-rst: None + # auth-redirect-addr: None + # ssl-mirror-intf: None + # identity-based-route: None + # natoutbound: None + # wanopt-profile: None + # per-ip-shaper: None + # profile-protocol-options: None + # diffserv-forward: None + # poolname: None + # comments: None + # label: None + # global-label: None + # firewall-session-dirty: None + # wanopt: None + # schedule: None + # internet-service-id: None + # auth-path: None + # vlan-cos-fwd: None + # custom-log-fields: None + # dstintf: None + # srcintf: None + # block-notification: None + # internet-service-src-id: None + # redirect-url: None + # waf-profile: None + # ntlm-enabled-browsers: None + # dscp-negate: None + # action: None + # fsso-agent-for-ntlm: None + # logtraffic: None + # vlan-filter: None + # policyid: 36 + # logtraffic-start: None + # webcache-https: None + # webfilter-profile: None + # internet-service-src: None + # webcache: None + # utm-status: None + # vpn_src_node: {'subnet': None, 'host': None, 'seq': None} + # ippool: None + # service: None + # wccp: None + # auto-asic-offload: None + # dscp-value: None + # url-category: None + # capture-packet: None + # adom: ansible + # inbound: None + # internet-service: None + # profile-type: None + # ssl-mirror: None + # srcaddr-negate: None + # gtp-profile: None + # mms-profile: None + # send-deny-packet: None + # devices: None + # permit-any-host: None + # av-profile: None + # internet-service-src-negate: None + # service-negate: None + # rsso: None + # app-group: None + # tcp-mss-sender: None + # natinbound: None + # fixedport: None + # ssl-ssh-profile: None + # outbound: None + # spamfilter-profile: None + # application-list: None + # application: None + # dnsfilter-profile: None + # nat: None + # fsso: None + # vlan-cos-rev: None + # status: None + # dsri: None + # users: None + # voip-profile: None + # dstaddr-negate: None + # traffic-shaper-reverse: None + # internet-service-custom: None + # diffserv-reverse: None + # srcaddr: None + # ssh-filter-profile: None + # delay-tcp-npu-session: None + # icap-profile: None + # captive-portal-exempt: None + # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None} + # app-category: None + # rtp-addr: None + # wsso: None + # tcp-mss-receiver: None + # dstaddr: None + # radius-mac-auth-bypass: None + # vpntunnel: None + ################################################## + ################################################## + # package_name: default + # wanopt-detection: None + # scan-botnet-connections: None + # profile-group: None + # dlp-sensor: None + # dscp-match: None + # replacemsg-override-group: None + # internet-service-negate: None + # np-acceleration: None + # learning-mode: None + # session-ttl: None + # ntlm-guest: None + # ips-sensor: None + # diffservcode-rev: None + # match-vip: None + # natip: None + # wanopt-peer: None + # traffic-shaper: None + # groups: None + # schedule-timeout: None + # name: Basic_IPv4_Policy_2 + # tcp-session-without-syn: None + # rtp-nat: None + # permit-stun-host: None + # natoutbound: None + # internet-service-src-custom: None + # mode: delete + # logtraffic: None + # ntlm: None + # auth-cert: None + # timeout-send-rst: None + # auth-redirect-addr: None + # ssl-mirror-intf: None + # identity-based-route: None + # diffservcode-forward: None + # wanopt-profile: None + # per-ip-shaper: None + # users: None + # diffserv-forward: None + # poolname: None + # comments: None + # label: None + # global-label: None + # firewall-session-dirty: None + # wanopt: None + # schedule: None + # internet-service-id: None + # auth-path: None + # vlan-cos-fwd: None + # custom-log-fields: None + # dstintf: None + # srcintf: None + # block-notification: None + # internet-service-src-id: None + # redirect-url: None + # waf-profile: None + # ntlm-enabled-browsers: None + # dscp-negate: None + # action: None + # fsso-agent-for-ntlm: None + # disclaimer: None + # vlan-filter: None + # dstaddr-negate: None + # logtraffic-start: None + # webcache-https: None + # webfilter-profile: None + # internet-service-src: None + # webcache: None + # utm-status: None + # vpn_src_node: {'subnet': None, 'host': None, 'seq': None} + # ippool: None + # service: None + # wccp: None + # auto-asic-offload: None + # dscp-value: None + # url-category: None + # capture-packet: None + # adom: ansible + # internet-service: None + # inbound: None + # profile-type: None + # ssl-mirror: None + # srcaddr-negate: None + # gtp-profile: None + # mms-profile: None + # send-deny-packet: None + # devices: None + # permit-any-host: None + # av-profile: None + # internet-service-src-negate: None + # service-negate: None + # rsso: None + # application-list: None + # app-group: None + # tcp-mss-sender: None + # natinbound: None + # fixedport: None + # ssl-ssh-profile: None + # outbound: None + # spamfilter-profile: None + # wanopt-passive-opt: None + # application: None + # dnsfilter-profile: None + # nat: None + # fsso: None + # vlan-cos-rev: None + # status: None + # dsri: None + # profile-protocol-options: None + # voip-profile: None + # policyid: 37 + # traffic-shaper-reverse: None + # internet-service-custom: None + # diffserv-reverse: None + # srcaddr: None + # dstaddr: None + # delay-tcp-npu-session: None + # icap-profile: None + # captive-portal-exempt: None + # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None} + # app-category: None + # rtp-addr: None + # wsso: None + # tcp-mss-receiver: None + # ssh-filter-profile: None + # radius-mac-auth-bypass: None + # vpntunnel: None + ################################################## + + # Test using fixture 1 # + output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 2 # + output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True + # Test using fixture 3 # + output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py new file mode 100644 index 000000000..f6bc82b71 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py @@ -0,0 +1,97 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_fwpol_package +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwpol_package.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_fwpol_package(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_fmgr_fwpol_package_folder(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py new file mode 100644 index 000000000..6620275cc --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py @@ -0,0 +1,216 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_ha +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_ha.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_set_ha_mode(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # fmgr_ha_peer_sn: None + # fmgr_ha_hb_threshold: 10 + # fmgr_ha_cluster_pw: fortinet + # fmgr_ha_peer_ipv6: None + # fmgr_ha_peer_status: None + # fmgr_ha_file_quota: 2048 + # fmgr_ha_cluster_id: 2 + # fmgr_ha_peer_ipv4: None + # fmgr_ha_hb_interval: 15 + # fmgr_ha_mode: master + # mode: set + ################################################## + ################################################## + # fmgr_ha_peer_sn: None + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: fortinet + # fmgr_ha_hb_interval: 5 + # fmgr_ha_cluster_id: 2 + # fmgr_ha_file_quota: 4096 + # fmgr_ha_peer_status: None + # fmgr_ha_peer_ipv4: None + # fmgr_ha_peer_ipv6: None + # fmgr_ha_mode: slave + # mode: set + ################################################## + ################################################## + # fmgr_ha_peer_sn: FMG-VMTM18001881 + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: fortinet + # fmgr_ha_peer_ipv6: None + # fmgr_ha_peer_status: enable + # fmgr_ha_file_quota: 4096 + # fmgr_ha_cluster_id: 2 + # fmgr_ha_peer_ipv4: 10.7.220.35 + # fmgr_ha_hb_interval: 5 + # fmgr_ha_mode: slave + # mode: set + ################################################## + ################################################## + # fmgr_ha_file_quota: 4096 + # fmgr_ha_cluster_pw: None + # fmgr_ha_peer_sn: None + # fmgr_ha_hb_interval: 5 + # fmgr_ha_cluster_id: 1 + # fmgr_ha_mode: standalone + # fmgr_ha_peer_status: None + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_peer_ipv4: None + # fmgr_ha_peer_ipv6: None + # mode: set + ################################################## + + # Test using fixture 1 # + output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_fmgr_get_ha_peer_list(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # fmgr_ha_peer_sn: FMG-VMTM18001882 + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: None + # fmgr_ha_peer_ipv6: None + # fmgr_ha_peer_status: enable + # fmgr_ha_file_quota: 4096 + # fmgr_ha_cluster_id: 1 + # fmgr_ha_peer_ipv4: 10.7.220.36 + # fmgr_ha_hb_interval: 5 + # fmgr_ha_mode: None + # mode: get + ################################################## + ################################################## + # fmgr_ha_peer_sn: FMG-VMTM18001881 + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: fortinet + # fmgr_ha_hb_interval: 5 + # fmgr_ha_cluster_id: 2 + # fmgr_ha_file_quota: 4096 + # fmgr_ha_peer_status: enable + # fmgr_ha_peer_ipv4: 10.7.220.35 + # fmgr_ha_peer_ipv6: None + # fmgr_ha_mode: slave + # mode: get + ################################################## + + # Test using fixture 1 # + output = fmgr_ha.fmgr_get_ha_peer_list(fmg_instance) + assert isinstance(output['raw_response'], list) is True + # Test using fixture 2 # + output = fmgr_ha.fmgr_get_ha_peer_list(fmg_instance) + assert isinstance(output['raw_response'], list) is True + + +def test_fmgr_set_ha_peer(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # fmgr_ha_peer_sn: FMG-VMTM18001882 + # next_peer_id: 2 + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: None + # fmgr_ha_peer_ipv6: None + # fmgr_ha_peer_status: enable + # fmgr_ha_file_quota: 4096 + # fmgr_ha_cluster_id: 1 + # peer_id: 1 + # fmgr_ha_peer_ipv4: 10.7.220.36 + # fmgr_ha_hb_interval: 5 + # fmgr_ha_mode: None + # mode: set + ################################################## + ################################################## + # fmgr_ha_peer_sn: FMG-VMTM18001881 + # next_peer_id: 1 + # fmgr_ha_hb_threshold: 3 + # fmgr_ha_cluster_pw: fortinet + # fmgr_ha_hb_interval: 5 + # fmgr_ha_cluster_id: 2 + # fmgr_ha_file_quota: 4096 + # fmgr_ha_peer_status: enable + # peer_id: 1 + # fmgr_ha_peer_ipv4: 10.7.220.35 + # fmgr_ha_peer_ipv6: None + # fmgr_ha_mode: slave + # mode: set + ################################################## + + # Test using fixture 1 # + output = fmgr_ha.fmgr_set_ha_peer(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_ha.fmgr_set_ha_peer(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py new file mode 100644 index 000000000..96325db1b --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py @@ -0,0 +1,64 @@ +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import pytest + +pytestmark = [] +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_provisioning + from .fortimanager_module import TestFortimanagerModule + from ansible_collections.community.fortios.tests.unit.plugins.modules.utils import set_module_args +except ImportError: + pytestmark.append(pytest.mark.skip("Could not load required modules for testing")) + +try: + from pyFMG.fortimgr import FortiManager +except ImportError: + pytestmark.append(pytest.mark.skip("FortiManager tests require pyFMG package")) + + +class TestFmgrProvisioningModule(TestFortimanagerModule): + + module = fmgr_provisioning + + def test_fmg_script_fail_connect(self): + set_module_args(dict(host='1.1.1.1', username='admin', password='admin', adom='root', + vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992', + platform='FortiGate-VM64', os_version='5.0', minor_release='6', + patch_release='0', os_type='fos')) + result = self.execute_module(failed=True) + self.assertEqual(result['msg'], 'Connection to FortiManager Failed') + + def test_fmg_script_login_fail_host(self): + set_module_args(dict(username='admin', password='admin', adom='root', + vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992', + platform='FortiGate-VM64', os_version='5.0', minor_release='6', + patch_release='0', os_type='fos')) + result = self.execute_module(failed=True) + self.assertEqual(result['msg'], 'missing required arguments: host') + + def test_fmg_script_login_fail_username(self): + set_module_args(dict(host='1.1.1.1', password='admin', adom='root', + vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992', + platform='FortiGate-VM64', os_version='5.0', minor_release='6', + patch_release='0', os_type='fos')) + result = self.execute_module(failed=True) + self.assertEqual(result['msg'], 'Host and username are required for connection') diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py new file mode 100644 index 000000000..a5470b680 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py @@ -0,0 +1,106 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_query +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_query.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_get_custom(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # custom_endpoint: /dvmdb/adom/ansible/script + # device_ip: None + # device_unique_name: None + # task_id: None + # adom: ansible + # nodes: None + # object: custom + # device_serial: None + # custom_dict: {'type': 'cli'} + # mode: get + ################################################## + + # Test using fixture 1 # + output = fmgr_query.fmgr_get_custom(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], list) is True + + +def test_fmgr_get_task_status(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # custom_endpoint: None + # object: task + # task_id: 247 + # adom: ansible + # device_ip: None + # custom_dict: None + # device_unique_name: None + # nodes: None + # device_serial: None + # mode: get + ################################################## + + # Test using fixture 1 # + output = fmgr_query.fmgr_get_task_status(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py new file mode 100644 index 000000000..c834414aa --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py @@ -0,0 +1,129 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_script +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_script.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_set_script(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # script_content: get system status + # adom: ansible + # script_scope: None + # script_name: TestScript + # script_target: remote_device + # mode: set + # script_description: Create by Ansible + # script_package: None + # vdom: root + # script_type: cli + ################################################## + + # Test using fixture 1 # + output = fmgr_script.set_script(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_delete_script(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # vdom: root + # script_target: None + # script_content: None + # adom: ansible + # script_description: None + # script_package: None + # mode: delete + # script_scope: None + # script_name: TestScript + # script_type: None + ################################################## + + # Test using fixture 1 # + output = fmgr_script.delete_script(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + + +def test_execute_script(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # script_content: None + # adom: ansible + # script_scope: FGT1 + # script_name: TestScript + # script_target: None + # mode: exec + # script_description: None + # script_package: None + # vdom: root + # script_type: None + ################################################## + + # Test using fixture 1 # + output = fmgr_script.execute_script(fmg_instance, fixture_data[0]['paramgram_used']) + assert isinstance(output['raw_response'], dict) is True diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py new file mode 100644 index 000000000..0af21b25c --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py @@ -0,0 +1,78 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_appctrl +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_appctrl.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_application_list_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 3 # + output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[2]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 4 # + output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[3]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py new file mode 100644 index 000000000..f3e0d5aec --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_av +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_av.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_antivirus_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_av.fmgr_antivirus_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_av.fmgr_antivirus_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py new file mode 100644 index 000000000..6e429fd24 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py @@ -0,0 +1,88 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_dns +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_dns.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_dnsfilter_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # comment: Created by Ansible Module TEST + # ftgd-dns: {'options': None, 'filters': {'action': None, 'category': None, 'log': None}} + # adom: root + # youtube-restrict: None + # sdns-domain-log: None + # block-botnet: None + # external-ip-blocklist: None + # block-action: block + # name: Ansible_DNS_Profile + # redirect-portal: None + # sdns-ftgd-err-log: None + # safe-search: None + # domain-filter: {'domain-filter-table': None} + # log-all-domain: None + # mode: set + ################################################## + + # Test using fixture 1 # + output = fmgr_secprof_dns.fmgr_dnsfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py new file mode 100644 index 000000000..487807523 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py @@ -0,0 +1,69 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_ips +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_ips.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_ips_sensor_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_ips.fmgr_ips_sensor_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py new file mode 100644 index 000000000..5c8fadde8 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py @@ -0,0 +1,112 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_profile_group +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_profile_group.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_firewall_profile_group_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # ssl-ssh-profile: None + # waf-profile: None + # adom: root + # webfilter-profile: None + # profile-protocol-options: None + # application-list: None + # icap-profile: None + # voip-profile: None + # ips-sensor: None + # dnsfilter-profile: None + # av-profile: None + # spamfilter-profile: None + # dlp-sensor: None + # mode: delete + # ssh-filter-profile: None + # mms-profile: None + # name: Ansible_TEST_Profile_Group + ################################################## + ################################################## + # ssl-ssh-profile: None + # application-list: None + # waf-profile: None + # adom: root + # webfilter-profile: None + # ips-sensor: None + # spamfilter-profile: None + # icap-profile: None + # dnsfilter-profile: None + # name: Ansible_TEST_Profile_Group + # voip-profile: None + # av-profile: Ansible_AV_Profile + # mode: set + # dlp-sensor: None + # mms-profile: None + # ssh-filter-profile: None + # profile-protocol-options: default + ################################################## + + # Test using fixture 1 # + output = fmgr_secprof_profile_group.fmgr_firewall_profile_group_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == -3 + # Test using fixture 2 # + output = fmgr_secprof_profile_group.fmgr_firewall_profile_group_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == -10131 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py new file mode 100644 index 000000000..61579327c --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_proxy +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_proxy.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_web_proxy_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_proxy.fmgr_web_proxy_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_proxy.fmgr_web_proxy_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py new file mode 100644 index 000000000..08e382b87 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_spam +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_spam.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_spamfilter_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_spam.fmgr_spamfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_spam.fmgr_spamfilter_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py new file mode 100644 index 000000000..0a0fa7bd2 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py @@ -0,0 +1,69 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_ssl_ssh +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_ssl_ssh.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_firewall_ssl_ssh_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + output = fmgr_secprof_ssl_ssh.fmgr_firewall_ssl_ssh_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + output = fmgr_secprof_ssl_ssh.fmgr_firewall_ssl_ssh_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py new file mode 100644 index 000000000..a13c654e5 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_voip +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_voip.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_voip_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_voip.fmgr_voip_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_voip.fmgr_voip_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py new file mode 100644 index 000000000..10b21a4c5 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py @@ -0,0 +1,69 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_waf +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_waf.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_waf_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + output = fmgr_secprof_waf.fmgr_waf_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + output = fmgr_secprof_waf.fmgr_waf_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py new file mode 100644 index 000000000..f6e2785b2 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py @@ -0,0 +1,72 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_wanopt +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_wanopt.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_wanopt_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + + # Test using fixture 1 # + output = fmgr_secprof_wanopt.fmgr_wanopt_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_wanopt.fmgr_wanopt_profile_modify(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py new file mode 100644 index 000000000..56bdd9a4a --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py @@ -0,0 +1,67 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler +import pytest + +try: + from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_web +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(autouse=True) +def module_mock(mocker): + connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule') + return connection_class_mock + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_web.Connection') + return connection_class_mock + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +fmg_instance = FortiManagerHandler(connection_mock, module_mock) + + +def test_fmgr_webfilter_profile_modify(fixture_data, mocker): + mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request', + side_effect=fixture_data) + output = fmgr_secprof_web.fmgr_webfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py new file mode 100644 index 000000000..66d2bcd2f --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json + +from ansible_collections.community.fortios.tests.unit.compat import unittest +from ansible_collections.community.fortios.tests.unit.compat.mock import patch +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes + + +def set_module_args(args): + if '_ansible_remote_tmp' not in args: + args['_ansible_remote_tmp'] = '/tmp' + if '_ansible_keep_remote_files' not in args: + args['_ansible_keep_remote_files'] = False + + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) + + +class AnsibleExitJson(Exception): + pass + + +class AnsibleFailJson(Exception): + pass + + +def exit_json(*args, **kwargs): + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class ModuleTestCase(unittest.TestCase): + + def setUp(self): + self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json) + self.mock_module.start() + self.mock_sleep = patch('time.sleep') + self.mock_sleep.start() + set_module_args({}) + self.addCleanup(self.mock_module.stop) + self.addCleanup(self.mock_sleep.stop) diff --git a/ansible_collections/community/fortios/tests/unit/requirements.txt b/ansible_collections/community/fortios/tests/unit/requirements.txt new file mode 100644 index 000000000..9c9a11414 --- /dev/null +++ b/ansible_collections/community/fortios/tests/unit/requirements.txt @@ -0,0 +1,4 @@ +unittest2 ; python_version <= '2.6' + +# requirements for FortiManager modules +pyFMG |