diff --git a/.ansible-lint b/.ansible-lint
index 78211f557..44d3018c6 100644
--- a/.ansible-lint
+++ b/.ansible-lint
@@ -8,6 +8,7 @@ exclude_paths:
- '.github/'
- 'roles/master_role_example/'
- 'changelogs/'
+ - 'tests/templated_role_example'
parseable: true
use_default_rules: true
# https://github.com/ansible/ansible-lint/issues/808
@@ -21,6 +22,7 @@ skip_list:
- meta-runtime # This collection with the appropriate awx.awx or ansible.controller still works with older ansible.
- role-name[path]
- sanity[cannot-ignore] # We're only ignoring sanity rules when we have to
+ - var-naming[no-role-prefix]
kinds:
- playbooks: "**/examples/templates/*.{yml,yaml}"
- playbooks: "**/examples/*.{yml,yaml}"
diff --git a/.ansible-lint-ignore b/.ansible-lint-ignore
new file mode 100644
index 000000000..b13484a1d
--- /dev/null
+++ b/.ansible-lint-ignore
@@ -0,0 +1,2 @@
+plugins/lookup/controller_object_diff.py yaml[document-end]
+plugins/modules/controller_export_diff.py yaml[document-end]
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 053c8650c..b01ac53a6 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -8,6 +8,7 @@ labels: bug, new
---
+
# Summary
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 451a12a00..0741163e6 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -2,6 +2,9 @@
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: false # default is true
contact_links:
+ - name: Help and Support
+ url: https://forum.ansible.com/tag/infra-config-as-code
+ about: We use the ansible forums for Annoucements, Getting Help, and more!
- name: Feature requests
url: https://github.com/redhat-cop/controller_configuration/discussions/categories/ideas
about: Suggest an idea for this project
diff --git a/ansible.cfg b/.github/files/ansible.cfg
similarity index 58%
rename from ansible.cfg
rename to .github/files/ansible.cfg
index d28da9a1c..34cfbf901 100644
--- a/ansible.cfg
+++ b/.github/files/ansible.cfg
@@ -1,4 +1,4 @@
[defaults]
-collections_paths=collections
+collections_paths=/home/runner/collections
roles_path=roles/
lookup_plugins=plugins/lookup/
diff --git a/galaxy.yml.j2 b/.github/files/galaxy.yml.j2
similarity index 92%
rename from galaxy.yml.j2
rename to .github/files/galaxy.yml.j2
index e4c57a0fe..12a31e8e5 100644
--- a/galaxy.yml.j2
+++ b/.github/files/galaxy.yml.j2
@@ -6,7 +6,7 @@ description: A collection of roles to manage Ansible Controller
readme: README.md
authors:
- Andrew Huffman
- - Jonathan Lozada De La Matta @jlozadad
+ - Adebisi Oyawale @aoyawale
- Kedar Kulkarni @kedark3
- Tom Page @Tompage1994
- Sean Sullivan @sean-m-sullivan
@@ -27,4 +27,5 @@ tags:
- collection
- controller_configuration
- automation_platform
+ - infrastructure
...
diff --git a/.github/workflows/ci_standalone.yml b/.github/workflows/ci_standalone.yml
index a3722811b..6040a803d 100644
--- a/.github/workflows/ci_standalone.yml
+++ b/.github/workflows/ci_standalone.yml
@@ -19,11 +19,11 @@ jobs:
matrix:
awx_version:
- devel
- - 21.13.0
- - 21.12.0
- - 21.11.0
- # - 20.1.0 Diabled until working
- # - 19.5.1 Diabled until working
+ - 23.3.1
+ - 23.3.0
+ - 23.0.0
+ - 22.7.0
uses: "./.github/workflows/ci_standalone_versioned.yml"
with:
awx_version: ${{ matrix.awx_version }}
+ gh_ref: ${{ github.event.pull_request.head.sha || github.sha }}
diff --git a/.github/workflows/ci_standalone_versioned.yml b/.github/workflows/ci_standalone_versioned.yml
index db5f369a4..30551587a 100644
--- a/.github/workflows/ci_standalone_versioned.yml
+++ b/.github/workflows/ci_standalone_versioned.yml
@@ -8,6 +8,11 @@ on:
description: The version to pull of awx
required: true
type: string
+ gh_ref:
+ description: The ref in the repository to pull
+ required: false
+ default: devel
+ type: string
env:
# Run docker-compose up in the background
COMPOSE_UP_OPTS: -d
@@ -17,17 +22,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
+ with:
+ ref: ${{ inputs.gh_ref }}
- - name: "Checkout galaxy_ng"
+ - name: Checkout AWX
uses: actions/checkout@v2
with:
repository: ansible/awx
path: awx
ref: ${{ inputs.awx_version }}
- - uses: actions/setup-python@v2
+ - uses: actions/setup-python@v4
with:
- python-version: "3.8"
+ python-version: "3.11"
- name: Update apt
run: sudo apt -y update
@@ -36,7 +43,7 @@ jobs:
run: sudo apt-get install -y libsasl2-dev python3-dev libldap2-dev libssl-dev build-essential
- name: Install docker-compose
- run: pip3 install --upgrade docker-compose
+ run: pip3 install --upgrade docker-compose pyyaml==5.3.1
- name: collect system info
run: whoami; id; pwd; ls -al; uname -a ; df -h .; mount ; cat /etc/issue; docker --version ; ps aux | fgrep -i docker; ls -al /var/run/containerd/containerd.sock
@@ -44,6 +51,10 @@ jobs:
- name: set the awx password in the inventory
run: echo "admin_password='password'" >> awx/tools/docker-compose/inventory
+ - name: Find and replace dependency
+ run: sed -i 's,rsyslog-8.2102.0-106.el9 ,https://download.copr.fedorainfracloud.org/results/ansible/Rsyslog/epel-9-x86_64/06076718-rsyslog/rsyslog-8.2102.0-106.el9.x86_64.rpm ,' tools/ansible/roles/dockerfile/templates/Dockerfile.j2
+ working-directory: awx
+
- name: build images
working-directory: awx
run: make docker-compose-build
@@ -56,15 +67,26 @@ jobs:
- name: give some time to spin up
run: sleep 30
+ - name: Move ansible.cfg to root
+ run: mv .github/files/ansible.cfg .
+
- name: Display Versions
run: which python && pip --version && ansible --version
+ - name: Build and install the collection
+ uses: redhat-cop/ansible_collections_tooling/actions/build_ansible_collection@main
+ with:
+ collection_namespace: infra
+ collection_name: controller_configuration
+ collection_version: 2.0.0
+ collection_repo: https://github.com/redhat-cop/controller_configuration/
+
- name: "Install Galaxy dependencies"
run: ansible-galaxy collection install -r .github/collections/requirements.yml
- name: "Perform playbook tests"
- run: ansible-playbook tests/configure_controller.yml -e controller_hostname=localhost:8043 -v
+ run: ansible-playbook tests/configure_controller.yml -e controller_hostname=localhost:8043 -v -e awx_version=${{ inputs.awx_version }}
- name: "Perform export model playbook tests"
- run: ansible-playbook tests/configure_controller_export_model.yml -e controller_hostname=localhost:8043 -v
+ run: ansible-playbook tests/configure_controller_export_model.yml -e controller_hostname=localhost:8043 -v -e awx_version=${{ inputs.awx_version }}
...
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f87e15ae0..ab4f63af7 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,29 +15,38 @@ jobs:
matrix:
awx_version:
- devel
- - 21.13.0
- - 21.12.0
+ - 22.4.0
+ - 22.3.0
- 21.11.0
- # - 20.1.0 Diabled until working
- # - 19.5.1 Diabled until working
uses: "./.github/workflows/ci_standalone_versioned.yml"
with:
awx_version: ${{ matrix.awx_version }}
release:
needs:
- ci_standalone
- uses: "redhat-cop/ansible_collections_tooling/.github/workflows/release_pipeline.yml@main"
+ uses: "redhat-cop/ansible_collections_tooling/.github/workflows/release_pipeline_dual.yml@main"
with:
- collection_namespace: infra
- collection_namespace_2: redhat_cop
- collection_name: controller_configuration
+ # Galaxy Publish
+ collection_namespace_1: infra
+ collection_name_1: controller_configuration
+ publish_url_collection_1: https://galaxy.ansible.com/api/
+ galaxy_publish_1: true
+ ah_publish_1: false
+ # CRC Publish
+ collection_namespace_2: infra
+ collection_name_2: controller_configuration
+ publish_url_collection_2: https://cloud.redhat.com/api/automation-hub/
+ galaxy_publish_2: false
+ ah_publish_2: true
collection_version: ${{ github.ref_name }}
collection_repo: https://github.com/redhat-cop/controller_configuration/
quay_username: redhat_cop
collection_dependencies: awx.awx
+ matrix_message: This Ansible collection allows for easy interaction with an AWX or Ansible Controller server via Ansible roles using the AWX/Controller collection modules.
secrets:
- galaxy_api_key: ${{ secrets.ANSIBLE_GALAXY_APIKEY }}
- infra_api_key: ${{ secrets.GALAXY_INFRA_KEY }}
- token: ${{ secrets.GITHUB_TOKEN }}
+ collection_api_key_1: ${{ secrets.GALAXY_INFRA_KEY }}
+ collection_api_key_2: ${{ secrets.CRC_PUBLISH_KEY }}
+ git_token: ${{ secrets.GITHUB_TOKEN }}
quay_token: ${{ secrets.quay_token }}
+ matrix_token: ${{ secrets.matrix_token }}
...
diff --git a/.gitignore b/.gitignore
index 188a8aadc..a1fc7799d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
collections/*
!collections/requirements.yml
-galaxy.yml
*.tar.gz
*.pyc
id_rsa*
test
tests/output
+.vscode
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index bc9f9cc01..3d85fda46 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,7 +1,7 @@
---
repos:
- repo: 'https://github.com/pre-commit/pre-commit-hooks'
- rev: v4.4.0
+ rev: v4.5.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
@@ -14,7 +14,7 @@ repos:
# types:
# - yaml
- repo: 'https://github.com/ansible-community/ansible-lint.git'
- rev: v6.14.3
+ rev: v6.22.0
hooks:
# see discussions here about what arguments are used, and behavior
# https://github.com/ansible/ansible-lint/issues/649
@@ -30,11 +30,11 @@ repos:
- "ansible-core>=2.13"
- "yamllint>=1.26,<2.0"
- repo: https://github.com/DavidAnson/markdownlint-cli2
- rev: v0.6.0
+ rev: v0.11.0
hooks:
- id: markdownlint-cli2
- repo: https://github.com/ambv/black
- rev: 23.1.0
+ rev: 23.11.0
hooks:
- id: black
name: black
@@ -42,7 +42,7 @@ repos:
args: [--config=.black.cfg, --check, --diff]
types: [python]
- repo: https://github.com/pycqa/flake8
- rev: 6.0.0
+ rev: 6.1.0
hooks:
- id: flake8
name: flake8
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 85ada7f19..76dc42da6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,14 +5,114 @@ infra.controller_configuration Release Notes
.. contents:: Topics
+v2.5.2
+======
+
+Bugfixes
+--------
+
+- Fixed issue with organization creation with instance group. Execute instance and instance_group before organizations.
+- dispatch - Fixed the order and behavior to run as a single task with options for organization behavior.
+- filetree_create - Fixed the misspelled variable name that caused exported job_templates yaml files containing incorrect name.
+- filetree_create and object_diff- Subelement filter is executed before when and it was causing a failure when the list was not defined.
+
+v2.5.1
+======
+
+Minor Changes
+-------------
+
+- Adds request_timeout to controller_export_diff module, and roles
+- licence role now uses a boolean of controller_license.use_looup to determine whether to lookup subscriptions. A lookup is only needed to refresh the available pools, or if it has never been done. See Role Readme for details.
+
+Bugfixes
+--------
+
+- Fixed issue with licence role not operating properly, when a controller never had credentials provided for subscription lookup. See Role Readme for proper usuage.
+- Fixed issue with organization role not acceppting default environments option correctly.
+
+v2.5.0
+======
+
+Minor Changes
+-------------
+
+- Added roles option to roles role to allow setting multiple roles in one item rather than repeating entire sections of code
+- ansible.cfg removed from root and galaxy.yml added to enable install from source
+
+Bugfixes
+--------
+
+- Added more attributes to be expanded and used by the comparison
+- Fixed lintering issues
+
+v2.4.1
+======
+
+Minor Changes
+-------------
+
+- Add option to change async directory, and set the default to null. /tmp/.ansible_async was a workaround while the default was broken previously.
+- Change from lookup to query in the object_diff task files
+- add organizations tag in a dispatch task which is in charge of applying galaxy credencitals in the organization.
+- added the instance_groups filed to the roles role.
+- added the possibility to export schedules through the filetree_create role
+- filetree_create now allows to export objects for the specified organization
+- remove depencency of CONTROLER_USERNAME variable for object_diff role by calling the API with api/me instead of calling the api/users and filtering by username
+
+Bugfixes
+--------
+
+- Changes default value for `*_enforce_defaults` to false instead of the truthy value (due to the quotes), 'false'.
+- Fix addition of `state: present` when `with_present: true`
+- Temporarily fixed an error when installing docker-compose using pip (see https://stackoverflow.com/questions/76708329/docker-compose-no-longer-building-image-attributeerror-cython-sources for more information)
+- When exporting job templates it was failing when missing some input information.
+- When exporting schedules, the diff_mode was not treated correctly
+- When importing the exported notification templates, the types of some values are not as expected.
+- When importing the exported settings, fields like `AUTOMATION_ANALYTICS_LAST_GATHER: 2023-07-17T13:22:06.445818Z` caused problems with the multiple `:`.
+- fix 'credentials' role ignoring 'update_secrets false' and forcing to default 'true'
+- fixed an the users and teams field on the roles role to be correct and not singular.
+
+v2.4.0
+======
+
+Minor Changes
+-------------
+
+- Added Roles bulk_host_create, bulk_job_launch.
+- Added new_name option to the roles applications, credential_types, execution_environments, inventories, projects, users.
+- Added new_username option to user role.
+- Added option to multiple roles to enforce defaults. This is described in each of the roles readmes and will slowly be rolled out to all applicable roles. This option enforces module/api defaults in order to prevent config drift. This makes it so if an option is NOT specified in a configuration it enforces the default value. It is not enabled by default.
+- Added scm_branch option to inventory_sources role.
+- Corrected various readmes.
+- Credentials role credential type set to mandatory. This would fail in the past if it was not set, this just codifies it.
+- If someone wants to have the old behavior, or only update projects with dispatch, the dispatch variable controller_configuration_dispatcher_roles can be overwritten and customized.
+- Instances role - changed default of node_type and node_state to omit, as generally these cannot be changed on existing instances unless deploying new instances.
+- Inventory role - added input_inventories option for constructed inventories.
+- Removed project_update from dispatch. This is because with bringing update_project option in line with the module options, it was running twice both in project and project update. Since both roles use the same variable controller_projects.
+- Set the default behavior of project_update to run the update as true, unless the user explicitly sets the variable update_project to overide the default behavior. This is because if the user is specifically calling project_update it should by default update the project.
+- Updated workflow job template options to use non depreciated names for options. This should not affect any operations.
+- added alias's for applicable roles to use the variables set by the awx cli export.
+- added get_stats.yml playbook in the playbook folder to get some basic info on a Tower/Controller instance
+- added option for using the export form of default execution environment.
+- added option to roles role to support upcoming change to allow lists of teams and users to be used in the module.
+- added options to license role to allow use of subcription lookup or pool_id.
+
+Bugfixes
+--------
+
+- Fixed defaults for values that are lists.
+- Fixed filetree read to error when organization not defined.
+- Fixed rrule in schedules to not be mandatory.
+
v2.3.1
======
Bugfixes
--------
+- Added argument_spec for all roles
- Ensures vars get loaded properly by dispatch role
-- Fixed issue in filetree_read where arg spec incorrect and caused failure (#550)
v2.3.0
======
@@ -24,6 +124,7 @@ Minor Changes
- Add new type of objects for object_diff role: applications, execution environments, instance groups, notifications and schedules
- Add no_log to all tasks that populates data to avoid exposing encrypted data
- Add task to add Galaxy credentials and Execution Environments to Organization.
+- Added argument_spec for all roles
- Set the variables to assign_galaxy_credentials_to_org and assign_default_ee_to_org to false in the task to run all roles at dispatch role.
- avoid to create orgs during drop_diff
- fixed an extra blank line in schedules readme that was breaking the table
@@ -37,7 +138,6 @@ Breaking Changes / Porting Guide
Bugfixes
--------
-- Added argument_spec for all roles
- Fixed name of task for inventory source update
- Fixed variable definitions in readmes
- Removed master_role_example as no longer required (this wasn't a functional role)
diff --git a/EXPORT_README.md b/EXPORT_README.md
index d02612d90..b63fa3aa1 100644
--- a/EXPORT_README.md
+++ b/EXPORT_README.md
@@ -14,7 +14,7 @@ This command allows exporting all available endpoints for Automation Controller
pip3 install awxkit
```
-## Basic command options
+## Basic command options and export methods
```console
awx export --conf.host https://localhost --conf.username admin --conf.password ******** --conf.insecure --help
@@ -24,18 +24,65 @@ awx export --conf.host https://localhost --conf.username admin --conf.password *
awx export --conf.host https://localhost --conf.username admin --conf.password ******** --conf.insecure --job_templates
```
+```yaml
+---
+- name: Export projects
+ hosts: localhost
+ connection: local
+ gather_facts: false
+ collections:
+ - ansible.controller
+ environment:
+ CONTROLLER_HOST: https://localhost
+ CONTROLLER_USERNAME: admin
+ CONTROLLER_PASSWORD: password
+ CONTROLLER_VERIFY_SSL: False
+
+ tasks:
+ - name: Export projects
+ awx.awx.export: # or ansible.controller.export
+ projects: all
+ register: export_results
+
+ - name: Show results
+ ansible.builtin.debug:
+ var: export_results
+
+ - name: Export projects to file
+ ansible.builtin.copy:
+ content: "{{ export_results | to_nice_yaml(width=50, explicit_start=True, explicit_end=True) }}"
+ dest: projects.yaml
+...
+```
+
## Available options for this command
|Option|
|:---:|
-|users|
-|organizations|
-|teams|
-|credential_types|
+|applications|
|credentials|
-|notification_templates|
-|projects|
+|credential_types|
+|execution_environments|
|inventory|
|inventory_sources|
|job_templates|
+|notification_templates|
+|organizations|
+|projects|
+|schedules|
+|teams|
+|users|
|workflow_job_templates|
+
+## Limitations
+
+### Project export
+
+related signature_validation_credential is exported as a credential # not an object.
+
+### Workflow export related items
+
+related instanced groups for workflow nodes prompt on launch for job templates
+related labels for workflow nodes prompt on launch for job templates
+
+Keep up to date with these limitations with [this awx issue](https://github.com/ansible/awx/issues/13868)
diff --git a/README.md b/README.md
index 2c0dbe853..71fa463a5 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,14 @@
This Ansible collection allows for easy interaction with an AWX or Ansible Controller server via Ansible roles using the AWX/Controller collection modules.
+## Getting Help
+
+We are on the Ansible Forums and Matrix, if you want to discuss something, ask for help, or participate in the community, please use the #infra-config-as-code tag on the fourm, or post to the chat in Matrix.
+
+[Ansible Forums](https://forum.ansible.com/tag/infra-config-as-code)
+
+[Matrix Chat Room](https://matrix.to/#/#aap_config_as_code:ansible.com)
+
## Requirements
The awx.awx or ansible.controller collections MUST be installed in order for this collection to work. It is recommended they be invoked in the playbook in the following way.
@@ -22,15 +30,21 @@ The awx.awx or ansible.controller collections MUST be installed in order for thi
- awx.awx
```
-## Red Hat Communities of Practice Configuration Collections Suite
+## Links to Ansible Automation Platform Collections
+
+| Collection Name | Purpose |
+|:--------------------------------------------------------------------------------------------:|:----------------------------------------:|
+| [awx.awx/Ansible.controller repo](https://github.com/ansible/awx/tree/devel/awx_collection) | Automation controller modules |
+| [Ansible Hub Configuration](https://github.com/ansible/automation_hub_collection) | Automation hub configuration |
+
+## Links to other Validated Configuration Collections for Ansible Automation Platform
-|Collection Name|Purpose|
-|:---:|:---:|
-|[Controller Configuration](https://galaxy.ansible.com/redhat_cop/controller_configuration)|Automation controller configuration|
-|[Hub Configuration](https://galaxy.ansible.com/redhat_cop/ah_configuration)|Automation hub configuration|
-|[EE Utilities](https://galaxy.ansible.com/redhat_cop/ee_utilities)|Execution Environment creation utilities|
-|[AAP installation Utilities](https://galaxy.ansible.com/redhat_cop/aap_utilities)|Ansible Automation Platform Utilities|
-|[AAP Configuration Template](https://github.com/redhat-cop/aap_configuration_template)|Configuration Template for this suite|
+| Collection Name | Purpose |
+|:------------------------------------------------------------------------------------------:|:----------------------------------------:|
+| [Controller Configuration](https://github.com/redhat-cop/controller_configuration) | Automation controller configuration |
+| [EE Utilities](https://github.com/redhat-cop/ee_utilities) | Execution Environment creation utilities |
+| [AAP installation Utilities](https://github.com/redhat-cop/aap_utilities) | Ansible Automation Platform Utilities |
+| [AAP Configuration Template](https://github.com/redhat-cop/aap_configuration_template) | Configuration Template for this suite |
## Included content
@@ -136,6 +150,7 @@ The input data can be organized in a very flexible way, letting the user use any
### Controller Export
The awx command line can export json that is compatible with this collection.
+In addition there is an awx.awx/ansible.controller export module that use the awx command line to export.
More details can be found [here](EXPORT_README.md)
### Template Example
diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml
index 7b116cc24..5af973336 100644
--- a/changelogs/.plugin-cache.yaml
+++ b/changelogs/.plugin-cache.yaml
@@ -13,6 +13,14 @@ objects:
description: An Ansible Role to create Applications on Ansible Controller.
name: applications
version_added: null
+ bulk_host_create:
+ description: An Ansible Role to run a list of ad hoc commands on Ansible Controller.
+ name: bulk_host_create
+ version_added: null
+ bulk_job_launch:
+ description: An Ansible Role to run a list of ad hoc commands on Ansible Controller.
+ name: bulk_job_launch
+ version_added: null
credential_input_sources:
description: An Ansible Role to create Credential Input Sources on Ansible Controller.
name: credential_input_sources
@@ -156,10 +164,16 @@ plugins:
description: Return difference for objects from Controller API
name: controller_object_diff
version_added: null
- module: {}
+ module:
+ controller_export_diff:
+ description: Compare controller configuration resources with those defined in
+ code.
+ name: controller_export_diff
+ namespace: ''
+ version_added: null
netconf: {}
shell: {}
strategy: {}
test: {}
vars: {}
-version: 2.3.1
+version: 2.5.2
diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml
index 9241d55e4..2d1ef090b 100644
--- a/changelogs/changelog.yaml
+++ b/changelogs/changelog.yaml
@@ -393,12 +393,12 @@ releases:
- Removed master_role_example as no longer required (this wasn't a functional
role)
minor_changes:
- - Added argument_spec for all roles
- Adapt filetree_read role tests playbook config-controller-filetree.yml.
- 'Add new type of objects for object_diff role: applications, execution environments,
instance groups, notifications and schedules'
- Add no_log to all tasks that populates data to avoid exposing encrypted data
- Add task to add Galaxy credentials and Execution Environments to Organization.
+ - Added argument_spec for all roles
- Set the variables to assign_galaxy_credentials_to_org and assign_default_ee_to_org
to false in the task to run all roles at dispatch role.
- avoid to create orgs during drop_diff
@@ -422,3 +422,149 @@ releases:
- arg_spec.yml
- dispatch_fix.yml
release_date: '2023-03-24'
+ 2.4.0:
+ changes:
+ bugfixes:
+ - Fixed defaults for values that are lists.
+ - Fixed filetree read to error when organization not defined.
+ - Fixed rrule in schedules to not be mandatory.
+ minor_changes:
+ - Added Roles bulk_host_create, bulk_job_launch.
+ - Added new_name option to the roles applications, credential_types, execution_environments,
+ inventories, projects, users.
+ - Added new_username option to user role.
+ - Added option to multiple roles to enforce defaults. This is described in each
+ of the roles readmes and will slowly be rolled out to all applicable roles.
+ This option enforces module/api defaults in order to prevent config drift.
+ This makes it so if an option is NOT specified in a configuration it enforces
+ the default value. It is not enabled by default.
+ - Added scm_branch option to inventory_sources role.
+ - Corrected various readmes.
+ - Credentials role credential type set to mandatory. This would fail in the
+ past if it was not set, this just codifies it.
+ - If someone wants to have the old behavior, or only update projects with dispatch,
+ the dispatch variable controller_configuration_dispatcher_roles can be overwritten
+ and customized.
+ - Instances role - changed default of node_type and node_state to omit, as generally
+ these cannot be changed on existing instances unless deploying new instances.
+ - Inventory role - added input_inventories option for constructed inventories.
+ - Removed project_update from dispatch. This is because with bringing update_project
+ option in line with the module options, it was running twice both in project
+ and project update. Since both roles use the same variable controller_projects.
+ - Set the default behavior of project_update to run the update as true, unless
+ the user explicitly sets the variable update_project to overide the default
+ behavior. This is because if the user is specifically calling project_update
+ it should by default update the project.
+ - Updated workflow job template options to use non depreciated names for options.
+ This should not affect any operations.
+ - added alias's for applicable roles to use the variables set by the awx cli
+ export.
+ - added get_stats.yml playbook in the playbook folder to get some basic info
+ on a Tower/Controller instance
+ - added option for using the export form of default execution environment.
+ - added option to roles role to support upcoming change to allow lists of teams
+ and users to be used in the module.
+ - added options to license role to allow use of subcription lookup or pool_id.
+ fragments:
+ - enforce_defaults.yml
+ - export_defaults.yml
+ - filetree_inventory_org.yml
+ - get_stats.yml
+ - license.yml
+ - list_default_fix.yml
+ - org_ee.yml
+ - project_update.yml
+ - role_updates.yml
+ - roles_update.yml
+ - rrule_bugfix.yml
+ release_date: '2023-06-09'
+ 2.4.1:
+ changes:
+ bugfixes:
+ - Changes default value for `*_enforce_defaults` to false instead of the truthy
+ value (due to the quotes), 'false'.
+ - 'Fix addition of `state: present` when `with_present: true`'
+ - Temporarily fixed an error when installing docker-compose using pip (see https://stackoverflow.com/questions/76708329/docker-compose-no-longer-building-image-attributeerror-cython-sources
+ for more information)
+ - When exporting job templates it was failing when missing some input information.
+ - When exporting schedules, the diff_mode was not treated correctly
+ - When importing the exported notification templates, the types of some values
+ are not as expected.
+ - 'When importing the exported settings, fields like `AUTOMATION_ANALYTICS_LAST_GATHER:
+ 2023-07-17T13:22:06.445818Z` caused problems with the multiple `:`.'
+ - fix 'credentials' role ignoring 'update_secrets false' and forcing to default
+ 'true'
+ - fixed an the users and teams field on the roles role to be correct and not
+ singular.
+ minor_changes:
+ - Add option to change async directory, and set the default to null. /tmp/.ansible_async
+ was a workaround while the default was broken previously.
+ - Change from lookup to query in the object_diff task files
+ - add organizations tag in a dispatch task which is in charge of applying galaxy
+ credencitals in the organization.
+ - added the instance_groups filed to the roles role.
+ - added the possibility to export schedules through the filetree_create role
+ - filetree_create now allows to export objects for the specified organization
+ - remove depencency of CONTROLER_USERNAME variable for object_diff role by calling
+ the API with api/me instead of calling the api/users and filtering by username
+ fragments:
+ - 610-filetree_create-now-allows-to-export-objects-for-the-specified-organization.yml
+ - 630-enforce-defs.yml
+ - add_organizations_tag.yml
+ - add_schedules_to_filetree_create.yml
+ - async.yml
+ - change_from_lookup_to_query.yml
+ - credentials_role_bugfix.yml
+ - filetree_create_bugfix.yml
+ - remove_username_dependency_objectdiff.yml
+ - roles_bugfix.yml
+ release_date: '2023-07-26'
+ 2.5.0:
+ changes:
+ bugfixes:
+ - Added more attributes to be expanded and used by the comparison
+ - Fixed lintering issues
+ minor_changes:
+ - Added roles option to roles role to allow setting multiple roles in one item
+ rather than repeating entire sections of code
+ - ansible.cfg removed from root and galaxy.yml added to enable install from
+ source
+ fragments:
+ - object_diff.yml
+ - roles.yml
+ - source_build.yml
+ release_date: '2023-08-03'
+ 2.5.1:
+ changes:
+ bugfixes:
+ - Fixed issue with licence role not operating properly, when a controller never
+ had credentials provided for subscription lookup. See Role Readme for proper
+ usuage.
+ - Fixed issue with organization role not acceppting default environments option
+ correctly.
+ minor_changes:
+ - Adds request_timeout to controller_export_diff module, and roles
+ - licence role now uses a boolean of controller_license.use_looup to determine
+ whether to lookup subscriptions. A lookup is only needed to refresh the available
+ pools, or if it has never been done. See Role Readme for details.
+ fragments:
+ - add_request_timeout.yml
+ - licence_org.yml
+ release_date: '2023-08-29'
+ 2.5.2:
+ changes:
+ bugfixes:
+ - Fixed issue with organization creation with instance group. Execute instance
+ and instance_group before organizations.
+ - dispatch - Fixed the order and behavior to run as a single task with options
+ for organization behavior.
+ - filetree_create - Fixed the misspelled variable name that caused exported
+ job_templates yaml files containing incorrect name.
+ - filetree_create and object_diff- Subelement filter is executed before when
+ and it was causing a failure when the list was not defined.
+ fragments:
+ - dispatch_bugfix.yml
+ - filetree_create_job_templates.yml
+ - fix_subelements_conditional.yml
+ - instancegroups_org.yml
+ release_date: '2023-10-14'
diff --git a/changelogs/fragments/checkmode.yml b/changelogs/fragments/checkmode.yml
new file mode 100644
index 000000000..c4a03a114
--- /dev/null
+++ b/changelogs/fragments/checkmode.yml
@@ -0,0 +1,5 @@
+---
+minor_changes:
+ - added mandatory check to workflow launch name option
+ - added improvements to checkmod where it will run faster with the async tasks. In addition added an additional fail check at end of dispatch that will likely fail if dependencies are missing, as expected.
+...
diff --git a/changelogs/fragments/constructed.yml b/changelogs/fragments/constructed.yml
new file mode 100644
index 000000000..d444c2af7
--- /dev/null
+++ b/changelogs/fragments/constructed.yml
@@ -0,0 +1,4 @@
+---
+bugfixes:
+ - The role 'inventory_sources' will now skip when the source parameter is `constructed`. These sources are auto created and not meant to be edited. However they can still be synced with the inventory_source_update.
+...
diff --git a/changelogs/fragments/diff_plugin.yml b/changelogs/fragments/diff_plugin.yml
new file mode 100644
index 000000000..90f868fee
--- /dev/null
+++ b/changelogs/fragments/diff_plugin.yml
@@ -0,0 +1,6 @@
+---
+bugfixes:
+ - Fixed an issue where the usage access to instance_groups were removed
+ - Fixed an issue where the diff doesn't work correctly when explicitly setting state present
+ - Fixed member removal of teams
+...
diff --git a/changelogs/fragments/filetree_create_export_constructed_inventories.yml b/changelogs/fragments/filetree_create_export_constructed_inventories.yml
new file mode 100644
index 000000000..ca538f982
--- /dev/null
+++ b/changelogs/fragments/filetree_create_export_constructed_inventories.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - filetree_create - Add the constructed inventory exportation fields from the API endpoint `api/v2/constructed_inventories`
diff --git a/changelogs/fragments/filtree_create_flatten_output.yml b/changelogs/fragments/filtree_create_flatten_output.yml
new file mode 100644
index 000000000..99529272f
--- /dev/null
+++ b/changelogs/fragments/filtree_create_flatten_output.yml
@@ -0,0 +1,4 @@
+---
+minor_changes:
+ - The role 'filetree_create' will now allow to export all the objects of one kind into a single file, so it can be loaded by both ansible `group_vars` syntax and `filetree_read` tool.
+...
diff --git a/docs/aap_config_as_code_public_meeting.ics b/docs/aap_config_as_code_public_meeting.ics
index 8ae6c226e..7b53de7c2 100644
--- a/docs/aap_config_as_code_public_meeting.ics
+++ b/docs/aap_config_as_code_public_meeting.ics
@@ -1,39 +1,25 @@
-BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-X-WR-CALNAME:AAP config as code Public meeting
-METHOD:PUBLISH
-PRODID:-//Apple Inc.//macOS 13.2.1//EN
-BEGIN:VEVENT
-TRANSP:OPAQUE
-DTEND:20230412T160000Z
-ORGANIZER;CN="ssulliva@redhat.com";EMAIL="ssulliva@redhat.com":mailto:ss
- ulliva@redhat.com
-UID:2k8fmfg2msr8lfi6k6g5upqt9a@google.com
-DTSTAMP:20230316T155301Z
-X-GOOGLE-CONFERENCE:https://meet.google.com/npj-fyzv-oyo
-DESCRIPTION:https://github.com/redhat-cop/controller_configuration/i
- ssues/475\n\n-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~
- :~:~:~:~:~:~:~:~:~:~:~:~::~:~::-\nJoin with Google Meet: https://meet.go
- ogle.com/npj-fyzv-oyo\nOr dial: (US) +1 470-722-0265 PIN: 621302239#\n\n
- Join using SIP\n1189446461569@gmeet.redhat.com (ID: 1189446461569)\nMore
- joining options: https://tel.meet/npj-fyzv-oyo?pin=1189446461569&hs=7\n
- \nLearn more about Meet at: https://support.google.com/a/users/answer/92
- 82720\n\nPlease do not edit this section.\n-::~:~::~:~:~:~:~:~:~:~:~:~:~
- :~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::-
-STATUS:CONFIRMED
-SEQUENCE:2
-SUMMARY:AAP config as code Public meeting
-DTSTART:20230412T150000Z
-LAST-MODIFIED:20230316T155150Z
-CREATED:20230123T211213Z
-BEGIN:VALARM
-UID:4555EBDE-771F-420A-9ED8-CB6C7540E67D
-X-WR-ALARMUID:4555EBDE-771F-420A-9ED8-CB6C7540E67D
-TRIGGER:-PT10M
-DESCRIPTION:This is an event reminder
-ACTION:DISPLAY
-END:VALARM
-END:VEVENT
-END:VCALENDAR
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ical.marudot.com//iCal Event Maker
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+DTSTAMP:20230418T084131Z
+UID:1681807271999-95396@ical.marudot.com
+DTSTART:20230511T130000Z
+RRULE:FREQ=WEEKLY;INTERVAL=4;BYDAY=TH
+DTEND:20230511T140000Z
+SUMMARY:AAP config as code Public meeting
+URL:https://meet.google.com/npj-fyzv-oyo
+X-GOOGLE-CONFERENCE:https://meet.google.com/npj-fyzv-oyo
+DESCRIPTION:https://github.com/redhat-cop/controller_configuration/i
+ ssues/475\n\n-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~
+ :~:~:~:~:~:~:~:~:~:~:~:~::~:~::-\nJoin with Google Meet: https://meet.go
+ ogle.com/npj-fyzv-oyo\nOr dial: (US) +1 470-722-0265 PIN: 621302239#\n\n
+ Join using SIP\n1189446461569@gmeet.redhat.com (ID: 1189446461569)\nMore
+ joining options: https://tel.meet/npj-fyzv-oyo?pin=1189446461569&hs=7\n
+ \nLearn more about Meet at: https://support.google.com/a/users/answer/92
+ 82720\n\nPlease do not edit this section.\n-::~:~::~:~:~:~:~:~:~:~:~:~:~
+ :~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::-
+END:VEVENT
+END:VCALENDAR
diff --git a/galaxy.yml b/galaxy.yml
new file mode 100644
index 000000000..260b4e458
--- /dev/null
+++ b/galaxy.yml
@@ -0,0 +1,31 @@
+---
+namespace: infra
+name: controller_configuration
+version: 2.5.2-devel
+description: A collection of roles to manage Ansible Controller
+readme: README.md
+authors:
+ - Andrew Huffman
+ - Adebisi Oyawale @aoyawale
+ - Kedar Kulkarni @kedark3
+ - Tom Page @Tompage1994
+ - Sean Sullivan @sean-m-sullivan
+ - David Danielsson @djdanielsson
+repository: https://github.com/redhat-cop/controller_configuration/
+issues: https://github.com/redhat-cop/controller_configuration//issues
+build_ignore:
+ - galaxy.yml.j2
+ - release.yml
+ - .github
+ - .ansiblelint.yml
+ - .yamllint.yml
+ - '*.tar.gz'
+license:
+ - GPL-3.0-or-later
+tags:
+ - controller
+ - collection
+ - controller_configuration
+ - automation_platform
+ - infrastructure
+...
diff --git a/playbooks/flatten_filetree_create_output.yaml b/playbooks/flatten_filetree_create_output.yaml
new file mode 100644
index 000000000..474e0f81b
--- /dev/null
+++ b/playbooks/flatten_filetree_create_output.yaml
@@ -0,0 +1,94 @@
+---
+- name: "Flatten the filetree_create output into unique files per each object type"
+ hosts: localhost
+ connection: local
+ gather_facts: false
+ vars:
+ filetree_controller_settings: &filetree_create_output_dir "{{ filetree_create_output_dir }}"
+ filetree_controller_organizations: *filetree_create_output_dir
+ filetree_controller_labels: *filetree_create_output_dir
+ filetree_controller_user_accounts: *filetree_create_output_dir
+ filetree_controller_teams: *filetree_create_output_dir
+ filetree_controller_credential_types: *filetree_create_output_dir
+ filetree_controller_credentials: *filetree_create_output_dir
+ filetree_controller_credential_input_sources: *filetree_create_output_dir
+ filetree_controller_notifications: *filetree_create_output_dir
+ filetree_controller_projects: *filetree_create_output_dir
+ filetree_controller_execution_environments: *filetree_create_output_dir
+ filetree_controller_applications: *filetree_create_output_dir
+ filetree_controller_inventories: *filetree_create_output_dir
+ filetree_controller_inventory_sources: *filetree_create_output_dir
+ filetree_controller_instance_groups: *filetree_create_output_dir
+ filetree_controller_hosts: *filetree_create_output_dir
+ filetree_controller_groups: *filetree_create_output_dir
+ filetree_controller_templates: *filetree_create_output_dir
+ filetree_controller_workflow_job_templates: *filetree_create_output_dir
+ filetree_controller_schedules: *filetree_create_output_dir
+ filetree_controller_roles: *filetree_create_output_dir
+ roles:
+ - infra.controller_configuration.filetree_read
+ post_tasks:
+ - name: "Create the output flatten dir"
+ ansible.builtin.file:
+ path: "{{ filetree_create_output_dir }}_flatten"
+ state: directory
+ mode: "0755"
+
+ - name: "Write all the objects to the corresponding file"
+ ansible.builtin.copy:
+ dest: "{{ filetree_create_output_dir }}_flatten/{{ object_type.name }}.yaml"
+ mode: "0644"
+ content: |
+ ---
+ {{ object_type.value | to_nice_yaml(indent=2) }}
+ ...
+ loop_control:
+ loop_var: object_type
+ loop:
+ - name: controller_settings
+ value: "{{ controller_settings }}"
+ - name: controller_organizations
+ value: "{{ controller_organizations }}"
+ - name: controller_labels
+ value: "{{ controller_labels }}"
+ - name: controller_user_accounts
+ value: "{{ controller_user_accounts }}"
+ - name: controller_teams
+ value: "{{ controller_teams }}"
+ - name: controller_credential_types
+ value: "{{ controller_credential_types }}"
+ - name: controller_credentials
+ value: "{{ controller_credentials }}"
+ - name: controller_credential_input_sources
+ value: "{{ controller_credential_input_sources }}"
+ - name: controller_notifications
+ value: "{{ controller_notifications }}"
+ - name: controller_projects
+ value: "{{ controller_projects }}"
+ - name: controller_execution_environments
+ value: "{{ controller_execution_environments }}"
+ - name: controller_applications
+ value: "{{ controller_applications }}"
+ - name: controller_inventories
+ value: "{{ controller_inventories }}"
+ - name: controller_inventory_sources
+ value: "{{ controller_inventory_sources }}"
+ - name: controller_instance_groups
+ value: "{{ controller_instance_groups }}"
+ - name: controller_hosts
+ value: "{{ controller_hosts }}"
+ - name: controller_groups
+ value: "{{ controller_groups }}"
+ - name: controller_templates
+ value: "{{ controller_templates }}"
+ - name: controller_workflow_job_templates
+ value: "{{ controller_workflow_job_templates | default([]) }}"
+ - name: controller_schedules
+ value: "{{ controller_schedules }}"
+ - name: controller_roles
+ value: "{{ controller_roles }}"
+...
+# Sample usage:
+#
+# ansible-playbook infra.controller_configuration.flatten_filetree_create_output.yaml -e '{filetree_create_output_dir: /tmp/filetree_output}'
+#
diff --git a/playbooks/get_stats.yml b/playbooks/get_stats.yml
new file mode 100644
index 000000000..f3d14e7ff
--- /dev/null
+++ b/playbooks/get_stats.yml
@@ -0,0 +1,114 @@
+---
+# This expects you to run this on Controller/Tower itself and use a system administrator account which you attach to the Job Template
+# You will also need to have localhost in your inventory for this to work without modification
+- name: Get stats
+ hosts: localhost
+ connection: local
+ gather_facts: true
+ vars:
+ # Using the Tower env names for backwards compatibility
+ controller_hostname: "{{ lookup('ansible.builtin.env', 'TOWER_HOST') }}"
+ controller_username: "{{ lookup('ansible.builtin.env', 'TOWER_USERNAME') }}"
+ controller_password: "{{ lookup('ansible.builtin.env', 'TOWER_PASSWORD') }}"
+ controller_validate_certs: "{{ lookup('ansible.builtin.env', 'TOWER_VERIFY_SSL') | default(false) }}"
+
+ tasks:
+ - name: Get number of JT
+ ansible.builtin.uri:
+ url: "https://{{ controller_hostname }}/api/v2/metrics/?format=json"
+ method: GET
+ force_basic_auth: true
+ user: "{{ controller_username }}"
+ password: "{{ controller_password }}"
+ return_content: true
+ headers:
+ Content-Type: application/json
+ validate_certs: false
+ register: r_metrics
+
+ - name: Debug metrics
+ ansible.builtin.debug:
+ verbosity: 1
+ msg:
+ - "{{ r_metrics }}"
+ - "{{ r_metrics['json']['awx_system_info'] }}"
+ - "{{ r_metrics['json']['awx_job_templates_total'] }}"
+ - "{{ r_metrics['json']['awx_workflow_job_templates_total'] }}"
+ - "{{ r_metrics['json']['awx_license_instance_total'] }}"
+ - "{{ r_metrics['json']['awx_license_instance_free'] }}"
+
+ - name: Get users info
+ ansible.builtin.uri:
+ url: "https://{{ controller_hostname }}/api/v2/users/?format=json"
+ method: GET
+ force_basic_auth: true
+ user: "{{ controller_username }}"
+ password: "{{ controller_password }}"
+ return_content: true
+ headers:
+ Content-Type: application/json
+ validate_certs: false
+ register: r_users
+
+ - name: Debug users
+ ansible.builtin.debug:
+ verbosity: 1
+ msg:
+ - "{{ r_users['json']['results'] }}"
+ - "{{ ansible_facts['date_time']['date'] | to_datetime('%Y-%m-%d') }}"
+ - "{{ r_users['json']['results'][0]['last_login'] | regex_search('[0-9]{4}-[0-9]{2}-[0-9]{2}', '\\0') | first }}"
+ - "{{ (r_users['json']['results'][0]['last_login'] | regex_search('[0-9]{4}-[0-9]{2}-[0-9]{2}', '\\0') | first) | to_datetime('%Y-%m-%d') }}"
+ - "{{ (((r_users['json']['results'][0]['last_login'] | regex_search('[0-9]{4}-[0-9]{2}-[0-9]{2}', '\\0') | first) | to_datetime('%Y-%m-%d')) - (ansible_facts['date_time']['date'] | to_datetime('%Y-%m-%d'))).days }}"
+
+ - name: Remove users who have never logged in (null)
+ ansible.builtin.set_fact:
+ temp_user_list: "{{ (active_users | default([])) + [item['last_login']] }}"
+ active_users: []
+ when: item['last_login'] is regex('[0-9]{4}-[0-9]{2}-[0-9]{2}(.*)')
+ loop: "{{ r_users['json']['results'] }}"
+
+ - name: Debug removing users list
+ ansible.builtin.debug:
+ verbosity: 1
+ msg:
+ - "{{ temp_user_list }}"
+
+ - name: Find active users
+ ansible.builtin.set_fact:
+ active_users: "{{ active_users + [item] }}"
+ # when: (((item | regex_search('[0-9]{4}-[0-9]{2}-[0-9]{2}', '\\0') | first) | to_datetime('%Y-%m-%d')) - ('2023-03-30' | to_datetime('%Y-%m-%d'))).days <= 30
+ when: ((((item | regex_search('[0-9]{4}-[0-9]{2}-[0-9]{2}', '\\0') | first) | to_datetime('%Y-%m-%d')) - (ansible_facts['date_time']['date'] | to_datetime('%Y-%m-%d'))).days) <= 30
+ loop: "{{ temp_user_list }}"
+
+ - name: Get subscription info
+ ansible.builtin.uri:
+ url: "https://{{ controller_hostname }}/api/v2/settings/all/?format=json"
+ method: GET
+ force_basic_auth: true
+ user: "{{ controller_username }}"
+ password: "{{ controller_password }}"
+ return_content: true
+ headers:
+ Content-Type: application/json
+ validate_certs: false
+ register: r_subscription
+
+ - name: Output
+ ansible.builtin.debug:
+ msg:
+ - "Number of active users: {{ active_users | length }}"
+ - "Number of subs: {{ r_metrics['json']['awx_license_instance_total']['samples'][0]['value'] }}"
+ - "Number of avalible subs: {{ r_metrics['json']['awx_license_instance_free']['samples'][0]['value'] }}"
+ - "Number of orgs: {{ r_metrics['json']['awx_organizations_total']['samples'][0]['value'] }}"
+ - "Number of users: {{ r_metrics['json']['awx_users_total']['samples'][0]['value'] }}"
+ - "Number of teams: {{ r_metrics['json']['awx_teams_total']['samples'][0]['value'] }}"
+ - "Number of inv: {{ r_metrics['json']['awx_inventories_total']['samples'][0]['value'] }}"
+ - "Number of projects: {{ r_metrics['json']['awx_projects_total']['samples'][0]['value'] }}"
+ - "Number of JT: {{ r_metrics['json']['awx_job_templates_total']['samples'][0]['value'] }}"
+ - "Number of workflows: {{ r_metrics['json']['awx_workflow_job_templates_total']['samples'][0]['value'] }}"
+ - "Number of hosts: {{ r_metrics['json']['awx_hosts_total']['samples'] }}"
+ - "{{ r_metrics['json']['awx_status_total']['samples'] }}"
+ - "{{ r_metrics['json']['awx_system_info']['samples'][0]['labels'] }}"
+ - "{{ r_subscription['json']['LICENSE'] }}"
+
+...
diff --git a/plugins/lookup/controller_object_diff.py b/plugins/lookup/controller_object_diff.py
index 33e1a0b66..1dd43ce30 100644
--- a/plugins/lookup/controller_object_diff.py
+++ b/plugins/lookup/controller_object_diff.py
@@ -67,16 +67,15 @@
- name: "Find the difference of Project between what is on the Controller versus curated list."
set_fact:
- project_difference: "{{ lookup('infra.controller_configuration.controller_object_diff',
+ project_difference: "{{ query('infra.controller_configuration.controller_object_diff',
api_list=controller_api_results, compare_list=differential_item.differential_test_items,
- with_present=true, set_absent=true ) }}"
+ with_present=true, set_absent=true) }}"
- name: Add Projects
include_role:
name: infra.controller_configuration.projects
vars:
controller_projects: "{{ project_difference }}"
-
"""
RETURN = """
@@ -89,11 +88,11 @@
returned: on successful differential
"""
-from ansible.plugins.lookup import LookupBase
+import copy
from ansible.errors import AnsibleError, AnsibleLookupError
from ansible.module_utils._text import to_native
+from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
-import copy
class LookupModule(LookupBase):
@@ -105,6 +104,27 @@ def handle_error(self, **kwargs):
def warn_callback(self, warning):
self.display.warning(warning)
+ def create_present_list(self, compare_list):
+ if not compare_list and not isinstance(compare_list, list):
+ return [compare_list]
+
+ for item in compare_list:
+ item.update({"state": "present"})
+
+ return compare_list
+
+ def map_item(self, item, new_attribute_name, attribute_value, dupitems):
+ new_item = copy.deepcopy(item)
+ for dupitem in [dupitem for dupitem in dupitems if dupitem in new_item]:
+ new_item.pop(dupitem)
+ new_item.update({new_attribute_name: attribute_value})
+ return new_item
+
+ def equal_dicts(self, d1, d2, ignore_keys):
+ d1_filtered = {k: v for k, v in d1.items() if k not in ignore_keys}
+ d2_filtered = {k: v for k, v in d2.items() if k not in ignore_keys}
+ return d1_filtered == d2_filtered
+
def run(self, terms, variables=None, **kwargs):
self.set_options(direct=kwargs)
@@ -114,10 +134,11 @@ def run(self, terms, variables=None, **kwargs):
warn_on_empty_api = self.get_option("warn_on_empty_api")
if not api_list:
if warn_on_empty_api:
- self._display.warning("Skipping, did not find items in api_list")
+ if not compare_list:
+ self._display.warning("Skipping, did not find items in neither api_list nor compare_list")
else:
raise AnsibleLookupError("Unable to find items in api_list")
- return [api_list]
+ return self.create_present_list(compare_list)
# Set Keys to keep for each list. Depending on type
if api_list[0]["type"] == "organization" or api_list[0]["type"] == "credential_type" or api_list[0]["type"] == "instance_group":
@@ -169,7 +190,12 @@ def run(self, terms, variables=None, **kwargs):
api_list_reduced = copy.deepcopy(api_list)
elif api_list[0]["type"] == "instance_group":
compare_list_reduced = [{key: item[key] for key in keys_to_keep} for item in compare_list]
- api_list_reduced = [{key: item[key] for key in api_keys_to_keep} for item in api_list if item["summary_fields"]["user_capabilities"]["delete"]]
+ api_list_reduced = [
+ {key: item[key] for key in api_keys_to_keep}
+ for item in api_list
+ if (item["summary_fields"] and item["summary_fields"]["user_capabilities"]["delete"])
+ ]
+
else:
compare_list_reduced = [{key: item[key] for key in keys_to_keep} for item in compare_list]
api_list_reduced = [{key: item[key] for key in api_keys_to_keep} for item in api_list]
@@ -186,7 +212,7 @@ def run(self, terms, variables=None, **kwargs):
item.pop("summary_fields")
elif api_list[0]["type"] == "credential":
for item in api_list_reduced:
- item.update({"organization": item["summary_fields"]["organization"]["name"]})
+ item.update({"organization": item["summary_fields"]["organization"]["name"] if item["summary_fields"]["organization"] else ""})
item.update({"credential_type": item["summary_fields"]["credential_type"]["name"]})
item.pop("summary_fields")
elif api_list[0]["type"] == "workflow_job_template_node":
@@ -202,7 +228,9 @@ def run(self, terms, variables=None, **kwargs):
for item in api_list_reduced:
if item["resource_type"] == "organization":
item.update({"organizations": [item[item["resource_type"]]]})
- item.update({"role": item["name"].lower()})
+ if item["resource_type"] == "instance_group":
+ item.update({"instance_groups": [item[item["resource_type"]]]})
+ item.update({"role": item["name"].lower().replace(" ", "_")})
# Remove the extra fields
item.pop("users")
item.pop("teams")
@@ -210,48 +238,64 @@ def run(self, terms, variables=None, **kwargs):
item.pop("resource_type")
if "organization" in item:
item.pop("organization")
+ if "instance_group" in item:
+ item.pop("instance_group")
if "type" in item:
item.pop("type")
list_to_extend = []
list_to_remove = []
for item in compare_list_reduced:
- target_teams_expanded = False
- job_templates_expanded = False
- workflows_expanded = False
+ expanded = False
+ dupitems = [
+ "target_team",
+ "target_teams",
+ "job_template",
+ "job_templates",
+ "workflow",
+ "workflows",
+ "inventory",
+ "inventories",
+ "project",
+ "projects",
+ "credential",
+ "credentials",
+ ]
+ if "target_team" in item:
+ list_to_extend.append(self.map_item(item, "team", item["target_team"], dupitems))
+ expanded = True
if "target_teams" in item:
for team in item["target_teams"]:
- new_item = copy.deepcopy(item)
- new_item.update({"team": team})
- new_item.pop("target_teams")
- if "job_templates" in new_item:
- new_item.pop("job_templates")
- if "workflows" in new_item:
- new_item.pop("workflows")
- list_to_extend.append(new_item)
- target_teams_expanded = True
+ list_to_extend.append(self.map_item(item, "team", team, dupitems))
+ expanded = True
+ if "job_template" in item:
+ list_to_extend.append(self.map_item(item, "job_template", item["job_template"], dupitems))
+ expanded = True
if "job_templates" in item:
for job_template in item["job_templates"]:
- new_item = copy.deepcopy(item)
- new_item.update({"job_template": job_template})
- new_item.pop("job_templates")
- if "target_teams" in new_item:
- new_item.pop("target_teams")
- if "workflows" in new_item:
- new_item.pop("workflows")
- list_to_extend.append(new_item)
- job_templates_expanded = True
+ list_to_extend.append(self.map_item(item, "job_template", job_template, dupitems))
+ expanded = True
+ if "workflow" in item:
+ list_to_extend.append(self.map_item(item, "workflow_job_template", item["workflow"], dupitems))
+ expanded = True
if "workflows" in item:
for workflow in item["workflows"]:
- new_item = copy.deepcopy(item)
- new_item.update({"workflow_job_template": workflow})
- new_item.pop("workflows")
- if "target_teams" in new_item:
- new_item.pop("target_teams")
- if "job_templates" in new_item:
- new_item.pop("job_templates")
- list_to_extend.append(new_item)
- workflows_expanded = True
- if target_teams_expanded or job_templates_expanded or workflows_expanded:
+ list_to_extend.append(self.map_item(item, "workflow_job_template", workflow, dupitems))
+ expanded = True
+ if "inventory" in item:
+ list_to_extend.append(self.map_item(item, "inventory", item["inventory"], dupitems))
+ expanded = True
+ if "inventories" in item:
+ for inventory in item["inventories"]:
+ list_to_extend.append(self.map_item(item, "inventory", inventory, dupitems))
+ expanded = True
+ if "project" in item:
+ list_to_extend.append(self.map_item(item, "project", item["project"], dupitems))
+ expanded = True
+ if "projects" in item:
+ for project in item["projects"]:
+ list_to_extend.append(self.map_item(item, "project", project, dupitems))
+ expanded = True
+ if expanded:
list_to_remove.append(item)
for item in list_to_remove:
compare_list_reduced.remove(item)
@@ -276,16 +320,23 @@ def run(self, terms, variables=None, **kwargs):
else:
difference = []
for item in api_list_reduced:
- if item not in compare_list_reduced:
+ for compare_item in compare_list_reduced:
+ if self.equal_dicts(compare_item, item, "state"):
+ break
+ else:
difference.append(item)
# Set
if self.get_option("set_absent"):
for item in difference:
item.update({"state": "absent"})
+ if "team" in item and item["role"] == "member":
+ item.update({"target_team": item["team"]})
+ item.pop("team")
+
# Combine Lists
if self.get_option("with_present"):
- for item in compare_list_reduced:
+ for item in compare_list:
item.update({"state": "present"})
compare_list.extend(difference)
# Return Compare list with difference attached
diff --git a/plugins/modules/controller_export_diff.py b/plugins/modules/controller_export_diff.py
new file mode 100644
index 000000000..4b0b0d344
--- /dev/null
+++ b/plugins/modules/controller_export_diff.py
@@ -0,0 +1,337 @@
+#!/usr/bin/python
+# coding: utf-8 -*-
+# (c) 2017, John Westcott IV
+# based on the work of John Westcott
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"}
+
+
+DOCUMENTATION = """
+---
+module: controller_export_diff
+author: "Sean Sullivan (@sean-m-sullivan)"
+short_description: Compare controller configuration resources with those defined in code.
+description:
+ - Compare controller configuration resources with those defined in code.
+options:
+ all:
+ description:
+ - Export all assets
+ type: bool
+ default: 'False'
+ organizations:
+ description:
+ - organization names to export
+ type: list
+ elements: str
+ users:
+ description:
+ - user names to export
+ type: list
+ elements: str
+ teams:
+ description:
+ - team names to export
+ type: list
+ elements: str
+ credential_types:
+ description:
+ - credential type names to export
+ type: list
+ elements: str
+ credentials:
+ description:
+ - credential names to export
+ type: list
+ elements: str
+ execution_environments:
+ description:
+ - execution environment names to export
+ type: list
+ elements: str
+ notification_templates:
+ description:
+ - notification template names to export
+ type: list
+ elements: str
+ inventory_sources:
+ description:
+ - inventory soruces to export
+ type: list
+ elements: str
+ inventory:
+ description:
+ - inventory names to export
+ type: list
+ elements: str
+ projects:
+ description:
+ - project names to export
+ type: list
+ elements: str
+ job_templates:
+ description:
+ - job template names to export
+ type: list
+ elements: str
+ workflow_job_templates:
+ description:
+ - workflow names to export
+ type: list
+ elements: str
+ applications:
+ description:
+ - OAuth2 application names to export
+ type: list
+ elements: str
+ schedules:
+ description:
+ - schedule names to export
+ type: list
+ elements: str
+ compare_items:
+ description:
+ - The dict of list objects to compare the api_list to.
+ - This should match the dictionary name for the object above, and will be used for comparison.
+ type: dict
+ required: True
+ set_absent:
+ description:
+ - Set state of items not in the compare list to 'absent'
+ type: bool
+ default: True
+ with_present:
+ description:
+ - Include items in the original compare list in the output, and set state to 'present'
+ type: bool
+ default: True
+ controller_host:
+ description:
+ - URL to your Automation Platform Controller instance.
+ - If value not set, will try environment variable C(CONTROLLER_HOST) and then config files
+ - If value not specified by any means, the value of C(127.0.0.1) will be used
+ type: str
+ aliases: [ tower_host ]
+ controller_username:
+ description:
+ - Username for your controller instance.
+ - If value not set, will try environment variable C(CONTROLLER_USERNAME) and then config files
+ type: str
+ aliases: [ tower_username ]
+ controller_password:
+ description:
+ - Password for your controller instance.
+ - If value not set, will try environment variable C(CONTROLLER_PASSWORD) and then config files
+ type: str
+ aliases: [ tower_password ]
+ controller_oauthtoken:
+ description:
+ - The OAuth token to use.
+ - This value can be in one of two formats.
+ - A string which is the token itself. (i.e. bqV5txm97wqJqtkxlMkhQz0pKhRMMX)
+ - A dictionary structure as returned by the token module.
+ - If value not set, will try environment variable C(CONTROLLER_OAUTH_TOKEN) and then config files
+ type: raw
+ aliases: [ tower_oauthtoken ]
+ validate_certs:
+ description:
+ - Whether to allow insecure connections to AWX.
+ - If C(no), SSL certificates will not be validated.
+ - This should only be used on personally controlled sites using self-signed certificates.
+ - If value not set, will try environment variable C(CONTROLLER_VERIFY_SSL) and then config files
+ type: bool
+ aliases: [ tower_verify_ssl ]
+ request_timeout:
+ description:
+ - Specify the timeout Ansible should use in requests to the controller host.
+ - Defaults to 10s, but this is handled by the shared module_utils code
+ - This option requires awx.awx>=22.7.0 or equivalent ansible.controller collection
+ type: float
+ version_added: "2.6.0"
+ controller_config_file:
+ description:
+ - Path to the controller config file.
+ - If provided, the other locations for config files will not be considered.
+ type: path
+ aliases: [tower_config_file]
+requirements:
+ - "awxkit >= 9.3.0"
+ - awx.awx or ansible.controller collection
+notes:
+ - Specifying a name of "all" for any asset type will export all items of that asset type.
+"""
+
+EXAMPLES = """
+- name: Get differential on projects and orgs.
+ infra.controller_configuration.controller_export_diff:
+ organizations: all
+ projects: all
+ compare_items:
+ organizations:
+ - name: Satellite
+ - name: Default
+ projects:
+ - name: Test Project
+ scm_type: git
+ scm_url: https://github.com/ansible/tower-example.git
+ scm_branch: master
+ scm_clean: true
+ description: Test Project 1
+ organization:
+ name: Default
+ wait: true
+ update_project: true
+ - name: Test Inventory source project with credential
+ scm_type: git
+ scm_url: https://github.com/ansible/ansible-examples.git
+ description: ansible-examples
+ organization:
+ name: Satellite
+ credential: gitlab-personal-access-token for satqe_auto_droid
+ wait: false
+ controller_host: https://controller
+ controller_username: admin
+ controller_password: secret123
+ validate_certs: false
+ register: export_results
+"""
+
+import logging
+from ansible.module_utils.six.moves import StringIO
+from copy import deepcopy
+
+try:
+ from ansible_collections.awx.awx.plugins.module_utils.awxkit import ControllerAWXKitModule
+except ImportError:
+ try:
+ from ansible_collections.ansible.controller.plugins.module_utils.awxkit import ControllerAWXKitModule
+ except ImportError:
+ AAP_IMPORT_ERROR = True
+
+try:
+ from awxkit.api.pages.api import EXPORTABLE_RESOURCES
+
+ HAS_EXPORTABLE_RESOURCES = True
+except ImportError:
+ HAS_EXPORTABLE_RESOURCES = False
+
+
+def main():
+ argument_spec = dict(
+ all=dict(type="bool", default=False),
+ applications=dict(type="list", elements="str"),
+ credential_types=dict(type="list", elements="str"),
+ credentials=dict(type="list", elements="str"),
+ execution_environments=dict(type="list", elements="str"),
+ inventory=dict(type="list", elements="str"),
+ inventory_sources=dict(type="list", elements="str"),
+ job_templates=dict(type="list", elements="str"),
+ notification_templates=dict(type="list", elements="str"),
+ organizations=dict(type="list", elements="str"),
+ projects=dict(type="list", elements="str"),
+ schedules=dict(type="list", elements="str"),
+ teams=dict(type="list", elements="str"),
+ users=dict(type="list", elements="str"),
+ workflow_job_templates=dict(type="list", elements="str"),
+ compare_items=dict(type="dict", required=True),
+ set_absent=dict(type="bool", default=True),
+ with_present=dict(type="bool", default=True),
+ )
+
+ module = ControllerAWXKitModule(argument_spec=argument_spec)
+
+ if not HAS_EXPORTABLE_RESOURCES:
+ module.fail_json(msg="Your version of awxkit does not have import/export")
+
+ compare_items = module.params.get("compare_items")
+ set_absent = module.params.get("set_absent")
+ with_present = module.params.get("with_present")
+ # The export process will never change the AWX system
+ module.json_output["changed"] = False
+
+ # The exporter code currently works like the following:
+ # Empty string == all assets of that type
+ # Non-Empty string = just one asset of that type (by name or ID)
+ # Asset type not present or None = skip asset type (unless everything is None, then export all)
+ # Here we are going to setup a dict of values to export
+ export_args = {}
+ for resource in EXPORTABLE_RESOURCES:
+ if module.params.get("all") or module.params.get(resource) == ["all"]:
+ # If we are exporting everything or we got the keyword "all" we pass in an empty string for this asset type
+ export_args[resource] = ""
+ else:
+ # Otherwise we take either the string or None (if the parameter was not passed) to get one or no items
+ resource_param = module.params.get(resource)
+ if resource_param is not None:
+ export_args[resource] = module.params.get(resource)
+
+ # Currently the export process does not return anything on error
+ # It simply just logs to Python's logger
+ # Set up a log gobbler to get error messages from export_assets
+ log_capture_string = StringIO()
+ ch = logging.StreamHandler(log_capture_string)
+ for logger_name in ["awxkit.api.pages.api", "awxkit.api.pages.page"]:
+ logger = logging.getLogger(logger_name)
+ logger.setLevel(logging.ERROR)
+ ch.setLevel(logging.ERROR)
+
+ logger.addHandler(ch)
+ log_contents = ""
+
+ # Run the export process
+ try:
+ awxkit_list = module.get_api_v2_object().export_assets(**export_args)
+ module.json_output["controller_objects"] = deepcopy(awxkit_list)
+ except Exception as e:
+ module.fail_json(msg="Failed to export assets {0}".format(e))
+ finally:
+ # Finally, consume the logs in case there were any errors and die if there were
+ log_contents = log_capture_string.getvalue()
+ log_capture_string.close()
+ if log_contents != "":
+ module.fail_json(msg=log_contents)
+
+ # Loop over each resource type that we gathered from the API.
+ output_list = {}
+ for resource in export_args:
+ try:
+ if resource in compare_items:
+ for resource_object in compare_items[resource]:
+ if with_present:
+ resource_object.update({"state": "present"})
+ for idx, dict_ in enumerate(awxkit_list[resource]):
+ if resource == "users":
+ if resource_object["username"] == dict_["username"]:
+ awxkit_list[resource].pop(idx)
+ elif "organization" not in resource_object or resource_object["organization"] is None:
+ if resource_object["name"] == dict_["name"]:
+ awxkit_list[resource].pop(idx)
+ else:
+ for idx, dict_ in enumerate(awxkit_list[resource]):
+ if resource_object["name"] == dict_["name"] and resource_object["organization"]["name"] == dict_["organization"]["name"]:
+ awxkit_list[resource].pop(idx)
+ # After looping through every item in the compare_items the remaining are set to absent.
+ if set_absent:
+ if awxkit_list[resource]:
+ for remaining_item in awxkit_list[resource]:
+ remaining_item.update({"state": "absent"})
+
+ if with_present:
+ output_list[resource] = compare_items[resource]
+ output_list[resource].extend(awxkit_list[resource])
+ else:
+ output_list[resource] = awxkit_list[resource]
+ except Exception as e:
+ module.fail_json(msg="Failed to export assets {0} with resource {1}".format(e, resource_object))
+ module.json_output["difference"] = output_list
+ module.exit_json(**module.json_output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/roles/ad_hoc_command/README.md b/roles/ad_hoc_command/README.md
index 6b703cf87..70f1a3410 100644
--- a/roles/ad_hoc_command/README.md
+++ b/roles/ad_hoc_command/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,6 +22,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_ad_hoc_commands`|`see below`|yes|Data structure describing your ad hoc commands to run Described below.||
### Secure Logging Variables
diff --git a/roles/ad_hoc_command/tasks/main.yml b/roles/ad_hoc_command/tasks/main.yml
index a469406f3..e8901266b 100644
--- a/roles/ad_hoc_command/tasks/main.yml
+++ b/roles/ad_hoc_command/tasks/main.yml
@@ -22,6 +22,7 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
diff --git a/roles/ad_hoc_command_cancel/README.md b/roles/ad_hoc_command_cancel/README.md
index c6e706543..7b1ffb7a4 100644
--- a/roles/ad_hoc_command_cancel/README.md
+++ b/roles/ad_hoc_command_cancel/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,6 +22,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_ad_hoc_commands_cancel`|`see below`|yes|Data structure describing your ad hoc jobs to cancel Described below.||
### Secure Logging Variables
diff --git a/roles/ad_hoc_command_cancel/tasks/main.yml b/roles/ad_hoc_command_cancel/tasks/main.yml
index 638332af2..18e4f0c1f 100644
--- a/roles/ad_hoc_command_cancel/tasks/main.yml
+++ b/roles/ad_hoc_command_cancel/tasks/main.yml
@@ -11,6 +11,7 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
diff --git a/roles/applications/README.md b/roles/applications/README.md
index 9ec9c71fd..68c69d618 100644
--- a/roles/applications/README.md
+++ b/roles/applications/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Applications on Ansible Controller.
+An Ansible Role to create/update/remove Applications on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
-|`controller_applications`|`see below`|yes|Data structure describing your applications, described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_applications`|`see below`|yes|Data structure describing your applications, described below. Alias: applications ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_applications_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_applications_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_applications_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_applications_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,6 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`name`|""|yes|str|Name of application|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`organization`|""|yes|str|Name of the organization for the application|
|`description`|""|no|str|Description to use for the application.|
|`authorization_grant_type`|"password"|yes|str|Grant type for tokens in this application, "password" or "authorization-code"|
diff --git a/roles/applications/defaults/main.yml b/roles/applications/defaults/main.yml
index 792d5240c..f578abea8 100644
--- a/roles/applications/defaults/main.yml
+++ b/roles/applications/defaults/main.yml
@@ -4,4 +4,6 @@ controller_applications: []
controller_configuration_applications_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_applications_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_applications_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_applications_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/applications/meta/argument_specs.yml b/roles/applications/meta/argument_specs.yml
index bc2524c7b..3da902379 100644
--- a/roles/applications/meta/argument_specs.yml
+++ b/roles/applications/meta/argument_specs.yml
@@ -62,6 +62,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/applications/meta/main.yml b/roles/applications/meta/main.yml
index 391b3f678..44b002e81 100644
--- a/roles/applications/meta/main.yml
+++ b/roles/applications/meta/main.yml
@@ -41,7 +41,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/applications/tasks/main.yml b/roles/applications/tasks/main.yml
index 84b5972ea..5f5eb7a0f 100644
--- a/roles/applications/tasks/main.yml
+++ b/roles/applications/tasks/main.yml
@@ -1,35 +1,44 @@
---
# Create Controller applications
-- name: Add Controller Applications
+- name: "Managing Controller Applications"
application:
name: "{{ __application_item.name | mandatory }}"
+ new_name: "{{ __application_item.new_name | default(omit, true) }}"
organization: "{{ __application_item.organization | mandatory }}"
- description: "{{ __application_item.description | default(omit, true) }}"
+ description: "{{ __application_item.description | default(('' if controller_configuration_applications_enforce_defaults else omit), true) }}"
authorization_grant_type: "{{ __application_item.authorization_grant_type | default('password') }}"
client_type: "{{ __application_item.client_type | default('public') }}"
redirect_uris: "{{ __application_item.redirect_uris | default([]) }}"
- skip_authorization: "{{ __application_item.skip_authorization | default(omit) }}"
+ skip_authorization: "{{ __application_item.skip_authorization | default((false if controller_configuration_applications_enforce_defaults else omit), true) }}"
state: "{{ __application_item.state | default(controller_state | default('present')) }}"
# Role specific options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_applications }}"
+ loop: "{{ applications if applications is defined else controller_applications }}"
loop_control:
loop_var: "__application_item"
+ label: "{{ __operation.verb }} Controller Application {{ __application_item.name }}"
no_log: "{{ controller_configuration_applications_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __applications_job_async
changed_when: not __applications_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__application_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Create Applications | Wait for finish the Applications creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __applications_job_async.failed is defined and __applications_job_async.failed
+
+- name: "Managing Controller Applications | Wait for finish the Application management"
ansible.builtin.async_status:
jid: "{{ __applications_job_async_results_item.ansible_job_id }}"
register: __applications_job_async_result
@@ -39,8 +48,10 @@
loop: "{{ __applications_job_async.results }}"
loop_control:
loop_var: __applications_job_async_results_item
- when: __applications_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Application {{ __applications_job_async_results_item.__application_item.name }} | Wait for finish the Application {{ __operation.action }}"
+ when: not ansible_check_mode and __applications_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_applications_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__applications_job_async_results_item.__application_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/bulk_host_create/README.md b/roles/bulk_host_create/README.md
new file mode 100644
index 000000000..6882a8b17
--- /dev/null
+++ b/roles/bulk_host_create/README.md
@@ -0,0 +1,142 @@
+# controller_configuration.bulk_host_create
+
+## Description
+
+An Ansible Role to create bulk hosts on Ansible Controller.
+
+## Requirements
+
+ansible-galaxy collection install -r tests/collections/requirements.yml to be installed
+Currently:
+ awx.awx
+ or
+ ansible.controller
+
+## Variables
+
+|Variable Name|Default Value|Required|Description|Example|
+|:---|:---:|:---:|:---|:---|
+|`controller_hostname`|""|yes|URL to the Ansible Controller Server.|127.0.0.1|
+|`controller_validate_certs`|`True`|no|Whether or not to validate the Ansible Controller Server's SSL certificate.||
+|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
+|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_configuration_bulk_hosts_secure_logging`|`see below`|yes|Data structure describing your organization or organizations Described below.||
+
+### Secure Logging Variables
+
+The following Variables compliment each other.
+If Both variables are not set, secure logging defaults to false.
+The role defaults to False as normally the add ******* task does not include sensitive information.
+controller_configuration_*******_secure_logging defaults to the value of controller_configuration_secure_logging if it is not explicitly called. This allows for secure logging to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_bulk_hosts_secure_logging`|`False`|no|Whether or not to include the sensitive ******* role tasks in the log. Set this value to `True` if you will be providing your sensitive values from elsewhere.|
+|`controller_configuration_secure_logging`|`False`|no|This variable enables secure logging as well, but is shared across multiple roles, see above.|
+
+### Asynchronous Retry Variables
+
+The following Variables set asynchronous retries for the role.
+If neither of the retries or delay or retries are set, they will default to their respective defaults.
+This allows for all items to be created, then checked that the task finishes successfully.
+This also speeds up the overall role.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_async_retries`|30|no|This variable sets the number of retries to attempt for the role globally.|
+|`controller_configuration_bulk_hosts_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
+|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
+|`controller_configuration_bulk_hosts_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
+
+## Data Structure
+
+### Bulk Host Variables
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`hosts`|""|yes|list|List of hosts and host options to add to inventory. Documented below|
+|`inventory`|""|yes|str|Inventory name or ID the hosts should be made a member of.|
+
+### Bulk Host Sub Options
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`name`|""|no|list|The name to use for the host.|
+|`description`|""|no|str|The description to use for the host.|
+|`enabled`|""|no|bool|If the host should be enabled.|
+|`variables`|""|no|dict|Variables to use for the host.|
+|`instance`|""|no|list|instance to use for the host.|
+
+### Standard Project Data Structure
+
+#### Json Example
+
+```json
+{
+ "controller_bulk_hosts": [
+ {
+ "inventory": "localhost",
+ "hosts": [
+ {
+ "name": "localhost"
+ },
+ {
+ "name": "127.0.0.1",
+ "variables": {
+ "some_var": "some_val",
+ "ansible_connection": "local"
+ }
+ }
+ ]
+ }
+ ]
+}
+```
+
+#### Yaml Example
+
+```yaml
+---
+controller_bulk_hosts:
+ - inventory: localhost
+ hosts:
+ - name: localhost
+ - name: 127.0.0.1
+ variables:
+ some_var: some_val
+ ansible_connection: local
+```
+
+## Playbook Examples
+
+### Standard Role Usage
+
+```yaml
+---
+- name: Playbook to configure ansible controller post installation
+ hosts: localhost
+ connection: local
+ # Define following vars here, or in controller_configs/controller_auth.yml
+ # controller_hostname: ansible-controller-web-svc-test-project.example.com
+ # controller_username: admin
+ # controller_password: changeme
+ pre_tasks:
+ - name: Include vars from controller_configs directory
+ include_vars:
+ dir: ./yaml
+ ignore_files: [controller_config.yml.template]
+ extensions: ["yml"]
+ roles:
+ - {role: redhat_cop.controller_configuration.bulk_host_create, when: controller_bulk_hosts is defined}
+```
+
+## License
+
+[MIT](https://github.com/redhat-cop/controller_configuration#licensing)
+
+## Author
+
+[Sean Sullivan](https://github.com/sean-m-sullivan)
diff --git a/roles/bulk_host_create/defaults/main.yml b/roles/bulk_host_create/defaults/main.yml
new file mode 100644
index 000000000..dcdea0ba4
--- /dev/null
+++ b/roles/bulk_host_create/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+controller_configuration_bulk_hosts_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
+controller_configuration_bulk_hosts_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
+controller_configuration_bulk_hosts_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+...
diff --git a/roles/bulk_host_create/meta/argument_specs.yml b/roles/bulk_host_create/meta/argument_specs.yml
new file mode 100644
index 000000000..a609ad810
--- /dev/null
+++ b/roles/bulk_host_create/meta/argument_specs.yml
@@ -0,0 +1,55 @@
+---
+argument_specs:
+ main:
+ short_description: An Ansible Role to run a list of ad hoc commands on Ansible Controller.
+ options:
+ controller_bulk_hosts:
+ description: Data structure describing a bulk of hosts to run
+ type: list
+ elements: dict
+
+ # Async variables
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
+
+ # No_log variables
+ controller_configuration_bulk_hosts_secure_logging:
+ default: "{{ controller_configuration_secure_logging | default(false) }}"
+ required: false
+ type: bool
+ description: Whether or not to include the sensitive ad_hoc_command role tasks in the log. Set this value to `true` if you will be providing your sensitive values from elsewhere.
+ controller_configuration_secure_logging:
+ default: false
+ required: false
+ type: bool
+ description: This variable enables secure logging across all roles as a default.
+
+ # Generic across all roles
+ controller_hostname:
+ default: None
+ required: false
+ description: URL to the Ansible Controller Server.
+ type: str
+ controller_validate_certs:
+ default: true
+ required: false
+ description: Whether or not to validate the Ansible Controller Server's SSL certificate.
+ type: str
+ controller_username:
+ default: None
+ required: false
+ description: Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.
+ type: str
+ controller_password:
+ default: None
+ required: false
+ description: Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.
+ type: str
+ controller_oauthtoken:
+ default: None
+ required: false
+ description: Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.
+ type: str
+...
diff --git a/roles/bulk_host_create/meta/main.yml b/roles/bulk_host_create/meta/main.yml
new file mode 100644
index 000000000..8d753a2e1
--- /dev/null
+++ b/roles/bulk_host_create/meta/main.yml
@@ -0,0 +1,46 @@
+---
+galaxy_info:
+ role_name: bulk_host_create
+ author: "Sean Sullivan"
+ description: "An Ansible Role to create hosts in bulk in Ansible Controller."
+ company: "Red Hat"
+
+ # If the issue tracker for your role is not on github, uncomment the
+ # next line and provide a value
+ # issue_tracker_url: http://example.com/issue/tracker
+ license: "MIT"
+
+ min_ansible_version: "2.8"
+
+ # Optionally specify the branch Galaxy will use when accessing the GitHub
+ # repo for this role. During role install, if no tags are available,
+ # Galaxy will use this branch. During import Galaxy will access files on
+ # this branch. If Travis integration is configured, only notifications for this
+ # branch will be accepted. Otherwise, in all cases, the repo's default branch
+ # (usually master) will be used.
+
+ # github_branch:
+
+ #
+ # platforms is a list of platforms, and each platform has a name and a list of versions.
+ #
+ platforms:
+ - name: "EL"
+ versions:
+ - "all"
+
+ galaxy_tags:
+ - "controller"
+ - "aap"
+ - "awx"
+ - "host"
+ - "hosts"
+
+collections:
+ - ansible.controller
+ - awx.awx
+
+dependencies: []
+# List your role dependencies here, one per line. Be sure to remove the '[]' above,
+# if you add dependencies to this list.
+...
diff --git a/roles/bulk_host_create/tasks/main.yml b/roles/bulk_host_create/tasks/main.yml
new file mode 100644
index 000000000..412476df8
--- /dev/null
+++ b/roles/bulk_host_create/tasks/main.yml
@@ -0,0 +1,46 @@
+---
+# Create Job Template
+- name: Add Controller hosts in bulk
+ bulk_host_create:
+ hosts: "{{ __controller_bulk_hosts_item.hosts }}"
+ inventory: "{{ __controller_bulk_hosts_item.inventory }}"
+
+ # Role Standard options
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ loop: "{{ controller_bulk_hosts }}"
+ loop_control:
+ loop_var: __controller_bulk_hosts_item
+ no_log: "{{ controller_configuration_bulk_hosts_secure_logging }}"
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
+ poll: 0
+ register: __controller_bulk_hosts_job_async
+ changed_when: not __controller_bulk_hosts_job_async.changed
+ vars:
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_bulk_hosts_job_async.failed is defined and __controller_bulk_hosts_job_async.failed
+
+- name: "Configure bulk_hosts | Wait for finish the bulk_hosts creation"
+ ansible.builtin.async_status:
+ jid: "{{ __controller_bulk_hosts_job_async_results_item.ansible_job_id }}"
+ register: __controller_bulk_hosts_job_async_result
+ until: __controller_bulk_hosts_job_async_result.finished
+ retries: "{{ controller_configuration_bulk_hosts_async_retries }}"
+ delay: "{{ controller_configuration_bulk_hosts_async_delay }}"
+ loop: "{{ __controller_bulk_hosts_job_async.results }}"
+ loop_control:
+ loop_var: __controller_bulk_hosts_job_async_results_item
+ when: not ansible_check_mode and __controller_bulk_hosts_job_async_results_item.ansible_job_id is defined
+ no_log: "{{ controller_configuration_bulk_hosts_secure_logging }}"
+ vars:
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+...
diff --git a/roles/bulk_job_launch/README.md b/roles/bulk_job_launch/README.md
new file mode 100644
index 000000000..79df2d895
--- /dev/null
+++ b/roles/bulk_job_launch/README.md
@@ -0,0 +1,140 @@
+# controller_configuration.bulk_job_launch
+
+## Description
+
+An Ansible Role to launch bulk jobs on Ansible Controller.
+
+## Requirements
+
+ansible-galaxy collection install -r tests/collections/requirements.yml to be installed
+Currently:
+ awx.awx
+ or
+ ansible.controller
+
+## Variables
+
+|Variable Name|Default Value|Required|Description|Example|
+|:---|:---:|:---:|:---|:---|
+|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
+|`controller_hostname`|""|yes|URL to the Ansible Controller Server.|127.0.0.1|
+|`controller_validate_certs`|`True`|no|Whether or not to validate the Ansible Controller Server's SSL certificate.||
+|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
+|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_bulk_launch_jobs`|`see below`|yes|Data structure describing your organization or organizations Described below.||
+
+### Secure Logging Variables
+
+The following Variables compliment each other.
+If Both variables are not set, secure logging defaults to false.
+The role defaults to False as normally the add ******* task does not include sensitive information.
+controller_configuration_*******_secure_logging defaults to the value of controller_configuration_secure_logging if it is not explicitly called. This allows for secure logging to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_bulk_job_launch_secure_logging`|`False`|no|Whether or not to include the sensitive bulk_job_launch role tasks in the log. Set this value to `True` if you will be providing your sensitive values from elsewhere.|
+|`controller_configuration_secure_logging`|`False`|no|This variable enables secure logging as well, but is shared across multiple roles, see above.|
+
+### Asynchronous Retry Variables
+
+The following Variables set asynchronous retries for the role.
+If neither of the retries or delay or retries are set, they will default to their respective defaults.
+This allows for all items to be created, then checked that the task finishes successfully.
+This also speeds up the overall role.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_async_retries`|30|no|This variable sets the number of retries to attempt for the role globally.|
+|`controller_configuration_bulk_job_launch_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
+|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
+|`controller_configuration_bulk_job_launch_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+
+## Data Structure
+
+### Bulk Host Variables
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`jobs`|""|yes|list|List of jobs and job options to launch. Documented below|
+|`description`|""|no|str|Optional description of this bulk job.|
+|`organization`|""|no|str|Organization for the bulk job. Affects who can see the resulting bulk job. If not provided, will use the organization the user is in.|
+|`inventory`|""|no|str|Inventory to use for the job, only used if prompt for inventory is set.|
+|`scm_branch`|""|no|str|A specific of the SCM project to run the template on.|
+|`extra_vars`|""|no|dict|extra_vars to use for the Job Template. ask_extra_vars needs to be set to True via controller_job_template module.|
+|`limit`|""|no|str|Limit to use for the job_template.|
+|`job_tags`|""|no|str|Specific tags to use for from playbook.|
+|`skip_tags`|""|no|str|Specific tags to skip from the playbook.|
+|`wait`|""|no|bool|Wait for the job to complete.|
+|`interval`|2|no|float|The interval to request an update from controller.|
+
+### Bulk Job Launch Sub Options
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`unified_job_template`|""|yes|int|The ID of object that is to be launched. Example objects include projects, inventory sources, and templates. Required if state='present.|
+|`inventory`|""|no|str|Inventory to use for the job, only used if prompt for inventory is set.|
+|`execution_environment`|Job Template default|no|str|Execution Environment applied as a prompt. Job Template default used if not set. Only allowed if `ask_execution_environment_on_launch` set to true on Job Template|
+|`instance_groups`|Job Template default|no|str| List of Instance Groups applied as a prompt. Job Template default used if not set. Only allowed if `ask_instance_groups_on_launch` set to true on Job Template|
+|`credentials`|""|no|list|TCredential to use for job, only used if prompt for credential is set.|
+|`labels`|Job Template default|no|list|List of labels to use in the job run. Job Template default used if not set. Only allowed if `ask_labels_on_launch` set to true on Job Template|
+|`extra_data`|""|no|dict|extra_data to use for the Job Template. ask_extra_vars needs to be set to True via controller_job_template module.|
+|`diff_mode`|""|no|bool|Show the changes made by Ansible tasks where supported.|
+|`verbosity`|""|no|int|Verbosity level for this job run.|
+|`scm_branch`|""|no|str|A specific of the SCM project to run the template on.|
+|`job_type`|""|no|str|Job_type to use for the job, only used if prompt for job_type is set. Run or Check are the options.|
+|`job_tags`|""|no|str|Specific tags to use for from playbook.|
+|`skip_tags`|""|no|str|Specific tags to skip from the playbook.|
+|`limit`|""|no|str|Limit to use for the job_template.|
+|`forks`|Job Template default|no|int|Forks applied as a prompt. Job Template default used if not set. Only allowed if `ask_forks_on_launch` set to true on Job Template|
+|`job_slice_count`|Job Template default|no|int|Job Slice Count to use in the job run. Job Template default used if not set. Only allowed if `ask_job_slice_count_on_launch` set to true on Job Template|
+|`identifier`|""|yes|str|An identifier for the resulting workflow node that represents this job that is unique within its workflow. It is copied to workflow job nodes corresponding to this node. This functions the same as the name field for other resources, however if it is not set, it will be set to a random UUID4 value.|
+|`timeout`|""|no|int|If waiting for the job to complete this will abort after this amount of seconds.|
+
+### Standard Project Data Structure
+
+#### Json Example
+
+```json
+{
+}
+
+```
+
+#### Yaml Example
+
+```yaml
+---
+```
+
+## Playbook Examples
+
+### Standard Role Usage
+
+```yaml
+---
+- name: Playbook to configure ansible controller post installation
+ hosts: localhost
+ connection: local
+ # Define following vars here, or in controller_configs/controller_auth.yml
+ # controller_hostname: ansible-controller-web-svc-test-project.example.com
+ # controller_username: admin
+ # controller_password: changeme
+ pre_tasks:
+ - name: Include vars from controller_configs directory
+ include_vars:
+ dir: ./yaml
+ ignore_files: [controller_config.yml.template]
+ extensions: ["yml"]
+ roles:
+ - {role: redhat_cop.controller_configuration.license, when: controller_license is defined}
+```
+
+## License
+
+[MIT](https://github.com/redhat-cop/controller_configuration#licensing)
+
+## Author
+
+[Sean Sullivan](https://github.com/sean-m-sullivan)
diff --git a/roles/bulk_job_launch/defaults/main.yml b/roles/bulk_job_launch/defaults/main.yml
new file mode 100644
index 000000000..745cc4f7d
--- /dev/null
+++ b/roles/bulk_job_launch/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+controller_configuration_bulk_job_launch_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
+controller_configuration_bulk_job_launch_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
+controller_configuration_bulk_job_launch_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+...
diff --git a/roles/bulk_job_launch/meta/argument_specs.yml b/roles/bulk_job_launch/meta/argument_specs.yml
new file mode 100644
index 000000000..f85ee8b3e
--- /dev/null
+++ b/roles/bulk_job_launch/meta/argument_specs.yml
@@ -0,0 +1,54 @@
+---
+argument_specs:
+ main:
+ short_description: An Ansible Role to run a list of ad hoc commands on Ansible Controller.
+ options:
+ controller_bulk_job_launch_commands:
+ description: Data structure describing your ad hoc commands to run
+ type: list
+ elements: dict
+
+ # No_log variables
+ controller_configuration_bulk_job_launch_secure_logging:
+ default: "{{ controller_configuration_secure_logging | default(false) }}"
+ required: false
+ type: bool
+ description: Whether or not to include the sensitive ad_hoc_command role tasks in the log. Set this value to `true` if you will be providing your sensitive values from elsewhere.
+ controller_configuration_secure_logging:
+ default: false
+ required: false
+ type: bool
+ description: This variable enables secure logging across all roles as a default.
+
+ # Generic across all roles
+ controller_state:
+ default: present
+ required: false
+ description: The state all objects will take unless overridden by object default
+ type: str
+ controller_hostname:
+ default: None
+ required: false
+ description: URL to the Ansible Controller Server.
+ type: str
+ controller_validate_certs:
+ default: true
+ required: false
+ description: Whether or not to validate the Ansible Controller Server's SSL certificate.
+ type: str
+ controller_username:
+ default: None
+ required: false
+ description: Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.
+ type: str
+ controller_password:
+ default: None
+ required: false
+ description: Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.
+ type: str
+ controller_oauthtoken:
+ default: None
+ required: false
+ description: Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.
+ type: str
+...
diff --git a/roles/bulk_job_launch/meta/main.yml b/roles/bulk_job_launch/meta/main.yml
new file mode 100644
index 000000000..c757301ed
--- /dev/null
+++ b/roles/bulk_job_launch/meta/main.yml
@@ -0,0 +1,46 @@
+---
+galaxy_info:
+ role_name: bulk_job_launch
+ author: "Sean Sullivan"
+ description: "An Ansible Role to launch bulk jobs in Ansible Controller."
+ company: "Red Hat"
+
+ # If the issue tracker for your role is not on github, uncomment the
+ # next line and provide a value
+ # issue_tracker_url: http://example.com/issue/tracker
+ license: "MIT"
+
+ min_ansible_version: "2.8"
+
+ # Optionally specify the branch Galaxy will use when accessing the GitHub
+ # repo for this role. During role install, if no tags are available,
+ # Galaxy will use this branch. During import Galaxy will access files on
+ # this branch. If Travis integration is configured, only notifications for this
+ # branch will be accepted. Otherwise, in all cases, the repo's default branch
+ # (usually master) will be used.
+
+ # github_branch:
+
+ #
+ # platforms is a list of platforms, and each platform has a name and a list of versions.
+ #
+ platforms:
+ - name: "EL"
+ versions:
+ - "all"
+
+ galaxy_tags:
+ - "controller"
+ - "aap"
+ - "awx"
+ - "job"
+ - "jobs"
+
+collections:
+ - ansible.controller
+ - awx.awx
+
+dependencies: []
+# List your role dependencies here, one per line. Be sure to remove the '[]' above,
+# if you add dependencies to this list.
+...
diff --git a/roles/bulk_job_launch/tasks/main.yml b/roles/bulk_job_launch/tasks/main.yml
new file mode 100644
index 000000000..3fb6237af
--- /dev/null
+++ b/roles/bulk_job_launch/tasks/main.yml
@@ -0,0 +1,33 @@
+---
+# Launch Controller Job
+- name: Bulk Launch Controller Jobs
+ bulk_job_launch:
+ jobs: "{{ __bulk_job_launch_item.jobs | mandatory }}"
+ name: "{{ __bulk_job_launch_item.name | default(omit, true) }}"
+ description: "{{ __bulk_job_launch_item.description | default(omit, true) }}"
+ organization: "{{ __bulk_job_launch_item.organization | default(omit, true) }}"
+ inventory: "{{ __bulk_job_launch_item.inventory | default(omit, true) }}"
+ scm_branch: "{{ __bulk_job_launch_item.scm_branch | default(omit, true) }}"
+ extra_vars: "{{ __bulk_job_launch_item.extra_vars | default(omit, true) }}"
+ limit: "{{ __bulk_job_launch_item.limit | default(omit, true) }}"
+ job_tags: "{{ __bulk_job_launch_item.tags | default(omit, true) }}"
+ skip_tags: "{{ __bulk_job_launch_item.skip_tags | default(omit, true) }}"
+ wait: "{{ __bulk_job_launch_item.wait | default(omit) }}"
+ interval: "{{ __bulk_job_launch_item.interval | default(omit) }}"
+
+ # Role Standard Options
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ loop: "{{ controller_bulk_launch_jobs }}"
+ loop_control:
+ loop_var: "__bulk_job_launch_item"
+ label: "{{ (__bulk_job_launch_item.organization | default('')) }}/{{ __bulk_job_launch_item.name }}"
+ no_log: "{{ controller_configuration_bulk_job_launch_secure_logging }}"
+ register: bulk_launched_controller_jobs
+ when: controller_bulk_launch_jobs is defined
+...
diff --git a/roles/credential_input_sources/README.md b/roles/credential_input_sources/README.md
index cb76c5d45..963f34f4c 100644
--- a/roles/credential_input_sources/README.md
+++ b/roles/credential_input_sources/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create credential input sources on Ansible Controller, the below example is for CyberArk as an input source, change accordingly to match your input source type.
+An Ansible Role to create/update/remove credential input sources on Ansible Controller, the below example is for CyberArk as an input source, change accordingly to match your input source type.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_credential_input_sources`|`see below`|yes|Data structure describing your credential input sources Described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_credential_input_sources_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_credential_input_sources_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_credential_input_sources_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_credential_input_sources_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/credential_input_sources/defaults/main.yml b/roles/credential_input_sources/defaults/main.yml
index c280593e8..b9ec68ea2 100644
--- a/roles/credential_input_sources/defaults/main.yml
+++ b/roles/credential_input_sources/defaults/main.yml
@@ -4,4 +4,6 @@ controller_credential_input_sources: []
controller_configuration_credential_input_sources_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_credential_input_sources_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_credential_input_sources_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_credential_input_sources_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/credential_input_sources/meta/argument_specs.yml b/roles/credential_input_sources/meta/argument_specs.yml
index ed3ec9e5e..c03c9c848 100644
--- a/roles/credential_input_sources/meta/argument_specs.yml
+++ b/roles/credential_input_sources/meta/argument_specs.yml
@@ -51,6 +51,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/credential_input_sources/meta/main.yml b/roles/credential_input_sources/meta/main.yml
index 444fdf8fb..c4c085400 100644
--- a/roles/credential_input_sources/meta/main.yml
+++ b/roles/credential_input_sources/meta/main.yml
@@ -45,7 +45,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/credential_input_sources/tasks/main.yml b/roles/credential_input_sources/tasks/main.yml
index 607a6eff9..462bd7f97 100644
--- a/roles/credential_input_sources/tasks/main.yml
+++ b/roles/credential_input_sources/tasks/main.yml
@@ -1,32 +1,40 @@
---
-- name: Add Controller Credential Input Sources
+- name: "Managing Controller Credential Input Sources"
credential_input_source:
target_credential: "{{ __cred_input_src_item.target_credential | mandatory }}"
input_field_name: "{{ __cred_input_src_item.input_field_name | mandatory }}"
source_credential: "{{ __cred_input_src_item.source_credential | default(omit, true) }}"
- description: "{{ __cred_input_src_item.description | default(omit, true) }}"
- metadata: "{{ __cred_input_src_item.metadata | default(omit, true) }}"
+ description: "{{ __cred_input_src_item.description | default(('' if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}"
+ metadata: "{{ __cred_input_src_item.metadata | default(({} if controller_configuration_credential_input_sources_enforce_defaults else omit), true) }}"
state: "{{ __cred_input_src_item.state | default(controller_state | default('present')) }}"
# Role specific options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_credential_input_sources }}"
loop_control:
loop_var: "__cred_input_src_item"
+ label: "{{ __operation.verb }} Controller Credential Input Source for Credential {{ __cred_input_src_item.target_credential }}"
no_log: "{{ controller_configuration_credential_input_sources_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __credential_input_sources_job_async
changed_when: not __credential_input_sources_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__cred_input_src_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Create Controller Credential Input Sources | Wait for finish the Controller Credential Input Sources creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __credential_input_sources_job_async.failed is defined and __credential_input_sources_job_async.failed
+
+- name: "Managing Controller Credential Input Sources | Wait for finish the Controller Credential Input Sources management"
ansible.builtin.async_status:
jid: "{{ __credential_input_sources_job_async_results_item.ansible_job_id }}"
register: __credential_input_sources_job_async_result
@@ -36,8 +44,10 @@
loop: "{{ __credential_input_sources_job_async.results }}"
loop_control:
loop_var: __credential_input_sources_job_async_results_item
- when: __credential_input_sources_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Credential Input Source for Credential {{ __credential_input_sources_job_async_results_item.__cred_input_src_item.target_credential }}"
+ when: not ansible_check_mode and __credential_input_sources_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_credential_input_sources_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__credential_input_sources_job_async_results_item.__cred_input_src_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/credential_types/README.md b/roles/credential_types/README.md
index 29b85821b..0443f91a8 100644
--- a/roles/credential_types/README.md
+++ b/roles/credential_types/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Credential Types on Ansible Controller.
+An Ansible Role to create/update/remove Credential Types on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
-|`controller_credential_types`|`see below`|yes|Data structure describing your credential types Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_credential_types`|`see below`|yes|Data structure describing your credential types Described below. Alias: credential_types ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_credential_types_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_credential_types_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -35,8 +50,8 @@ controller_configuration_credential_types_secure_logging defaults to the value o
|Variable Name|Default Value|Required|Description|
|:---:|:---:|:---:|:---:|
-|`controller_configuration_secure_logging`|`False`|no|Whether or not to include the sensitive Credential Type role tasks in the log. Set this value to `True` if you will be providing your sensitive values from elsewhere.|
-|`controller_configuration_credential_types_secure_logging`|`False`|no|This variable enables secure logging as well, but is shared across multiple roles, see above.|
+|`controller_configuration_credential_types_secure_logging`|`False`|no|Whether or not to include the sensitive Credential Type role tasks in the log. Set this value to `True` if you will be providing your sensitive values from elsewhere.|
+|`controller_configuration_secure_logging`|`False`|no|This variable enables secure logging as well, but is shared across multiple roles, see above.|
### Asynchronous Retry Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_credential_types_async_retries`|`controller_configuration_async_retries`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_credential_types_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,6 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Description|
|:---:|:---:|:---:|:---:|
|`name`|""|yes|Name of Credential Type|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`description`|`False`|no|The description of the credential type to give more detail about it.|
|`injectors`|""|no|Enter injectors using either JSON or YAML syntax. Refer to the Ansible controller documentation for example syntax. See below on proper formatting.|
|`inputs`|""|no|Enter inputs using either JSON or YAML syntax. Refer to the Ansible controller documentation for example syntax.|
diff --git a/roles/credential_types/defaults/main.yml b/roles/credential_types/defaults/main.yml
index b78362570..2ab36b6a4 100644
--- a/roles/credential_types/defaults/main.yml
+++ b/roles/credential_types/defaults/main.yml
@@ -4,4 +4,6 @@ controller_credential_types: []
controller_configuration_credential_types_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_credential_types_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_credential_types_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_credential_types_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/credential_types/meta/argument_specs.yml b/roles/credential_types/meta/argument_specs.yml
index 01bb2400a..94580d0a7 100644
--- a/roles/credential_types/meta/argument_specs.yml
+++ b/roles/credential_types/meta/argument_specs.yml
@@ -59,6 +59,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/credential_types/meta/main.yml b/roles/credential_types/meta/main.yml
index ea9933c0e..8617a76d0 100644
--- a/roles/credential_types/meta/main.yml
+++ b/roles/credential_types/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/credential_types/tasks/main.yml b/roles/credential_types/tasks/main.yml
index cb7eda3f1..9b79ced2f 100644
--- a/roles/credential_types/tasks/main.yml
+++ b/roles/credential_types/tasks/main.yml
@@ -1,10 +1,11 @@
---
-- name: Add Credential Types
+- name: "Managing Credential Types"
credential_type:
name: "{{ __controller_credential_type_item.name | mandatory }}"
- description: "{{ __controller_credential_type_item.description | default(omit, true) }}"
- injectors: "{{ __controller_credential_type_item.injectors | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
- inputs: "{{ __controller_credential_type_item.inputs | default(omit, true) }}"
+ new_name: "{{ __controller_credential_type_item.new_name | default(omit, true) }}"
+ description: "{{ __controller_credential_type_item.description | default(('' if controller_configuration_credential_types_enforce_defaults else omit), true) }}"
+ injectors: "{{ __controller_credential_type_item.injectors | default(({} if controller_configuration_credential_types_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
+ inputs: "{{ __controller_credential_type_item.inputs | default(({} if controller_configuration_credential_types_enforce_defaults else omit), true) }}"
kind: "{{ __controller_credential_type_item.kind | default('cloud') }}"
state: "{{ __controller_credential_type_item.state | default(controller_state | default('present')) }}"
@@ -12,21 +13,29 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_credential_types }}"
+ loop: "{{ credential_types if credential_types is defined else controller_credential_types }}"
loop_control:
loop_var: __controller_credential_type_item
+ label: "{{ __operation.verb }} Credential Type {{ __controller_credential_type_item.name }}"
no_log: "{{ controller_configuration_credential_types_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __credentialtypes_job_async
changed_when: not __credentialtypes_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_credential_type_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Credential Types | Wait for finish the credential types creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __credentialtypes_job_async.failed is defined and __credentialtypes_job_async.failed
+
+- name: "Managing Controller Credential Types | Wait for finish the credential types management"
ansible.builtin.async_status:
jid: "{{ __credentialtypes_job_async_result_item.ansible_job_id }}"
register: __credentialtypes_job_async_result
@@ -36,8 +45,10 @@
loop: "{{ __credentialtypes_job_async.results }}"
loop_control:
loop_var: __credentialtypes_job_async_result_item
- when: __credentialtypes_job_async_result_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Credential Type {{ __credentialtypes_job_async_result_item }} | Wait for finish the credential type {{ __operation.action }}"
+ when: not ansible_check_mode and __credentialtypes_job_async_result_item.ansible_job_id is defined
no_log: "{{ controller_configuration_credential_types_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__credentialtypes_job_async_result_item.__controller_credential_type_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/credentials/README.md b/roles/credentials/README.md
index c320bf656..4a7c61fd6 100644
--- a/roles/credentials/README.md
+++ b/roles/credentials/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Credentials on Ansible Controller.
+An Ansible Role to create/update/remove Credentials on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
-|`controller_credentials`|`see below`|yes|Data structure describing your credentials Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_credentials`|`see below`|yes|Data structure describing your credentials Described below. Alias: credentials ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_credentials_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_credentials_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_credentials_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_credentials_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,7 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Description|
|:---:|:---:|:---:|:---:|
|`name`|""|yes|Name of Credential|
-|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field.|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`copy_from`|""|no|Name or id to copy the credential from. This will copy an existing credential and change any parameters supplied.|
|`description`|`False`|no|Description of of Credential.|
|`organization`|""|no|Organization this Credential belongs to. If provided on creation, do not give either user or team.|
diff --git a/roles/credentials/defaults/main.yml b/roles/credentials/defaults/main.yml
index 95aad6486..adbac1567 100644
--- a/roles/credentials/defaults/main.yml
+++ b/roles/credentials/defaults/main.yml
@@ -4,4 +4,6 @@ controller_credentials: []
controller_configuration_credentials_secure_logging: "{{ controller_configuration_secure_logging | default(true) }}"
controller_configuration_credentials_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_credentials_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_credentials_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/credentials/meta/argument_specs.yml b/roles/credentials/meta/argument_specs.yml
index a9c171c14..f8b5f8a1e 100644
--- a/roles/credentials/meta/argument_specs.yml
+++ b/roles/credentials/meta/argument_specs.yml
@@ -72,6 +72,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/credentials/meta/main.yml b/roles/credentials/meta/main.yml
index 96e0f7f84..a3ab27bfb 100644
--- a/roles/credentials/meta/main.yml
+++ b/roles/credentials/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/credentials/tasks/main.yml b/roles/credentials/tasks/main.yml
index a5c67c1a8..74e46d13e 100644
--- a/roles/credentials/tasks/main.yml
+++ b/roles/credentials/tasks/main.yml
@@ -1,16 +1,16 @@
---
-- name: Add Credentials
+- name: "Managing Credentials"
credential:
name: "{{ __controller_credentials_item.name | mandatory }}"
new_name: "{{ __controller_credentials_item.new_name | default(omit, true) }}"
copy_from: "{{ __controller_credentials_item.copy_from | default(omit, true) }}"
- description: "{{ __controller_credentials_item.description | default(omit, true) }}"
- organization: "{{ __controller_credentials_item.organization.name | default(__controller_credentials_item.organization | default(omit, true)) }}"
- credential_type: "{{ __controller_credentials_item.credential_type.name | default(__controller_credentials_item.credential_type | default(omit, true)) }}"
- inputs: "{{ __controller_credentials_item.inputs | default(omit, true) }}"
- user: "{{ __controller_credentials_item.user.username | default(__controller_credentials_item.user | default(omit, true)) }}"
- team: "{{ __controller_credentials_item.team.name | default(__controller_credentials_item.team | default(omit, true)) }}"
- update_secrets: "{{ __controller_credentials_item.update_secrets | default(omit) }}"
+ description: "{{ __controller_credentials_item.description | default(('' if controller_configuration_credentials_enforce_defaults else omit), true) }}"
+ organization: "{{ __controller_credentials_item.organization.name | default(__controller_credentials_item.organization | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}"
+ credential_type: "{{ __controller_credentials_item.credential_type.name | default(__controller_credentials_item.credential_type | mandatory) }}"
+ inputs: "{{ __controller_credentials_item.inputs | default(({} if controller_configuration_credentials_enforce_defaults else omit), true) }}"
+ user: "{{ __controller_credentials_item.user.username | default(__controller_credentials_item.user | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}"
+ team: "{{ __controller_credentials_item.team.name | default(__controller_credentials_item.team | default(('' if controller_configuration_credentials_enforce_defaults else omit), true)) }}"
+ update_secrets: "{{ __controller_credentials_item.update_secrets | default(true if controller_configuration_credentials_enforce_defaults else omit) }}"
state: "{{ __controller_credentials_item.state | default(controller_state | default('present')) }}"
# Role specific options
@@ -20,19 +20,25 @@
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_credentials }}"
+ loop: "{{ credentials if credentials is defined else controller_credentials }}"
loop_control:
loop_var: __controller_credentials_item
- label: "{{ __controller_credentials_item.name | mandatory }}"
+ label: "{{ __operation.verb }} Credential {{ __controller_credentials_item.name }}"
no_log: "{{ controller_configuration_credentials_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __credentials_job_async
changed_when: not __credentials_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_credentials_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Credentials | Wait for finish the credential creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __credentials_job_async.failed is defined and __credentials_job_async.failed
+
+- name: "Managing Controller Credentials | Wait for finish the credential management"
ansible.builtin.async_status:
jid: "{{ __credentials_job_async_results_item.ansible_job_id }}"
register: __credentials_job_async_result
@@ -42,9 +48,10 @@
loop: "{{ __credentials_job_async.results }}"
loop_control:
loop_var: __credentials_job_async_results_item
- label: "{{ __credentials_job_async_results_item.__controller_credentials_item.name }}"
- when: __credentials_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Credential {{ __credentials_job_async_results_item.__controller_credentials_item.name }} | Wait for finish the credential {{ __operation.action }}"
+ when: not ansible_check_mode and __credentials_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_credentials_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_credentials_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/dispatch/README.md b/roles/dispatch/README.md
index 699755812..319f6db16 100644
--- a/roles/dispatch/README.md
+++ b/roles/dispatch/README.md
@@ -41,6 +41,8 @@ controller_configuration_dispatcher_roles:
- {role: workflow_job_templates, var: controller_workflows, tags: workflow_job_templates}
- {role: schedules, var: controller_schedules, tags: schedules}
- {role: roles, var: controller_roles, tags: roles}
+ - {role: job_launch, var: controller_launch_jobs, tags: job_launch}
+ - {role: workflow_launch, var: controller_workflow_launch_jobs, tags: workflow_launch}
```
Note that each item has three elements:
@@ -61,6 +63,7 @@ It is possible to redefine this variable with a subset of roles or with differen
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
### Secure Logging Variables
diff --git a/roles/dispatch/defaults/main.yml b/roles/dispatch/defaults/main.yml
index 3f9a1dcdb..f76bcab27 100644
--- a/roles/dispatch/defaults/main.yml
+++ b/roles/dispatch/defaults/main.yml
@@ -1,27 +1,88 @@
---
controller_configuration_dispatcher_roles:
- - {role: settings, var: controller_settings, tags: settings}
- - {role: organizations, var: controller_organizations, tags: organizations}
- - {role: labels, var: controller_labels, tags: labels}
- - {role: users, var: controller_user_accounts, tags: users}
- - {role: teams, var: controller_teams, tags: teams}
- - {role: credential_types, var: controller_credential_types, tags: credential_types}
- - {role: credentials, var: controller_credentials, tags: credentials}
- - {role: credential_input_sources, var: controller_credential_input_sources, tags: credential_input_sources}
- - {role: notification_templates, var: controller_notifications, tags: notification_templates}
- - {role: projects, var: controller_projects, tags: projects}
- - {role: inventories, var: controller_inventories, tags: inventories}
- - {role: inventory_sources, var: controller_inventory_sources, tags: inventory_sources}
- - {role: inventory_source_update, var: controller_inventory_sources, tags: inventory_sources}
- - {role: execution_environments, var: controller_execution_environments, tags: execution_environments}
- - {role: applications, var: controller_applications, tags: applications}
- - {role: instances, var: controller_instances, tags: instances}
- - {role: instance_groups, var: controller_instance_groups, tags: instance_groups}
- - {role: project_update, var: controller_projects, tags: projects}
- - {role: hosts, var: controller_hosts, tags: hosts}
- - {role: groups, var: controller_groups, tags: inventories}
- - {role: job_templates, var: controller_templates, tags: job_templates}
- - {role: workflow_job_templates, var: controller_workflows, tags: workflow_job_templates}
- - {role: schedules, var: controller_schedules, tags: schedules}
- - {role: roles, var: controller_roles, tags: roles}
+ - role: settings
+ var: controller_settings
+ tags: settings
+ - role: instances
+ var: controller_instances
+ tags: instances
+ - role: instance_groups
+ var: controller_instance_groups
+ tags: instance_groups
+ - role: organizations
+ var: controller_organizations
+ tags: organizations
+ assign_galaxy_credentials_to_org: false
+ assign_default_ee_to_org: false
+ - role: labels
+ var: controller_labels
+ tags: labels
+ - role: users
+ var: controller_user_accounts
+ tags: users
+ - role: teams
+ var: controller_teams
+ tags: teams
+ - role: credential_types
+ var: controller_credential_types
+ tags: credential_types
+ - role: credentials
+ var: controller_credentials
+ tags: credentials
+ - role: credential_input_sources
+ var: controller_credential_input_sources
+ tags: credential_input_sources
+ - role: execution_environments
+ var: controller_execution_environments
+ tags: execution_environments
+ - role: organizations
+ var: controller_organizations
+ tags: organizations
+ assign_galaxy_credentials_to_org: true
+ assign_default_ee_to_org: true
+ - role: notification_templates
+ var: controller_notifications
+ tags: notification_templates
+ - role: projects
+ var: controller_projects
+ tags: projects
+ - role: inventories
+ var: controller_inventories
+ tags: inventories
+ - role: inventory_sources
+ var: controller_inventory_sources
+ tags: inventory_sources
+ - role: inventory_source_update
+ var: controller_inventory_sources
+ tags: inventory_sources
+ - role: applications
+ var: controller_applications
+ tags: applications
+ - role: hosts
+ var: controller_hosts
+ tags: hosts
+ - role: bulk_host_create
+ var: controller_bulk_hosts
+ tags: bulk_hosts
+ - role: groups
+ var: controller_groups
+ tags: inventories
+ - role: job_templates
+ var: controller_templates
+ tags: job_templates
+ - role: workflow_job_templates
+ var: controller_workflows
+ tags: workflow_job_templates
+ - role: schedules
+ var: controller_schedules
+ tags: schedules
+ - role: roles
+ var: controller_roles
+ tags: roles
+ - role: job_launch
+ var: controller_launch_jobs
+ tags: job_launch
+ - role: workflow_launch
+ var: controller_workflow_launch_jobs
+ tags: workflow_launch
...
diff --git a/roles/dispatch/meta/argument_specs.yml b/roles/dispatch/meta/argument_specs.yml
index ade0c93f7..23bad66be 100644
--- a/roles/dispatch/meta/argument_specs.yml
+++ b/roles/dispatch/meta/argument_specs.yml
@@ -6,6 +6,8 @@ argument_specs:
controller_configuration_dispatcher_roles:
default:
- {role: settings, var: controller_settings, tags: settings}
+ - {role: instances, var: controller_instances, tags: instances}
+ - {role: instance_groups, var: controller_instance_groups, tags: instance_groups}
- {role: organizations, var: controller_organizations, tags: organizations}
- {role: labels, var: controller_labels, tags: labels}
- {role: users, var: controller_user_accounts, tags: users}
@@ -19,16 +21,17 @@ argument_specs:
- {role: inventory_sources, var: controller_inventory_sources, tags: inventory_sources}
- {role: inventory_source_update, var: controller_inventory_sources, tags: inventory_sources}
- {role: execution_environments, var: controller_execution_environments, tags: execution_environments}
+ - {role: organizations, var: controller_organizations, tags: organizations, assign_galaxy_credentials_to_org: true, assign_default_ee_to_org: true}
- {role: applications, var: controller_applications, tags: applications}
- - {role: instances, var: controller_instances, tags: instances}
- - {role: instance_groups, var: controller_instance_groups, tags: instance_groups}
- - {role: project_update, var: controller_projects, tags: projects}
- {role: hosts, var: controller_hosts, tags: hosts}
+ - {role: bulk_host_create, var: controller_bulk_hosts, tags: bulk_hosts}
- {role: groups, var: controller_groups, tags: inventories}
- {role: job_templates, var: controller_templates, tags: job_templates}
- {role: workflow_job_templates, var: controller_workflows, tags: workflow_job_templates}
- {role: schedules, var: controller_schedules, tags: schedules}
- {role: roles, var: controller_roles, tags: roles}
+ - {role: job_launch, var: controller_launch_jobs, tags: job_launch}
+ - {role: workflow_launch, var: controller_workflow_launch_jobs, tags: workflow_launch}
required: false
description: List of roles, variables and tags to run through
type: list
@@ -45,6 +48,14 @@ argument_specs:
tags:
required: false
description: Tags to be applied to the role so tagging can be used to run only part of a playbook
+ assign_galaxy_credentials_to_org:
+ required: false
+ description: Variable to be applied. Whether to assign the galaxy credential to the organizations. Only relevant against the organizations role.
+ default: false
+ assign_default_ee_to_org:
+ required: false
+ description: Variable to be applied. Whether to assign the default execution environment to the organizations. Only relevant against the organizations role.
+ default: false
# Async variables
diff --git a/roles/dispatch/tasks/main.yml b/roles/dispatch/tasks/main.yml
index 472fd8a49..4c661165c 100644
--- a/roles/dispatch/tasks/main.yml
+++ b/roles/dispatch/tasks/main.yml
@@ -1,5 +1,5 @@
---
-- name: "Run infra.controller_configuration.{{ __role.role }}"
+- name: "Run the following infra.controller_configuration roles: {{ controller_configuration_dispatcher_roles | map(attribute='role') | join(', ') }}"
ansible.builtin.include_role:
name: "{{ __role.role }}"
apply:
@@ -10,13 +10,11 @@
loop_control:
loop_var: __role
vars:
- assign_galaxy_credentials_to_org: false
- assign_default_ee_to_org: false
+ assign_galaxy_credentials_to_org: "{{ __role.assign_galaxy_credentials_to_org | default(false) }}"
+ assign_default_ee_to_org: "{{ __role.assign_default_ee_to_org | default(false) }}"
-- name: Include Tasks to add Galaxy credentials and Execution Environments to Organizations
- ansible.builtin.include_role:
- name: organizations
- apply:
- tags:
- - organizations
+- name: "Fail the playbook if there were errors (check mode only)"
+ ansible.builtin.fail:
+ msg: "The execution has failed because of errors (probably due to missing dependencies caused by check mode)."
+ when: ansible_check_mode and error_flag is defined and error_flag
...
diff --git a/roles/execution_environments/README.md b/roles/execution_environments/README.md
index 704a0ad7c..268bfdb5b 100644
--- a/roles/execution_environments/README.md
+++ b/roles/execution_environments/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create execution_environments on Ansible Controller.
+An Ansible Role to create/update/remove execution_environments on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
-|`controller_execution_environments`|`see below`|yes|Data structure describing your organization or organizations Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_execution_environments`|`see below`|yes|Data structure describing your organization or organizations Described below. Alias: execution_environments ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_execution_environments_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_execution_environments_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_execution_environments_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_execution_environments_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,6 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`name`|""|yes|str|Name of execution environment|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`description`|""|no|str|Description to use for the execution environment.|
|`image`|""|yes|str|Container image to use for the execution environment|
|`organization`|""|no|str|The organization the execution environment belongs to.|
diff --git a/roles/execution_environments/defaults/main.yml b/roles/execution_environments/defaults/main.yml
index ca3a83513..90c9a8e76 100644
--- a/roles/execution_environments/defaults/main.yml
+++ b/roles/execution_environments/defaults/main.yml
@@ -3,4 +3,6 @@
controller_configuration_execution_environments_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_execution_environments_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_execution_environments_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_execution_environments_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/execution_environments/meta/argument_specs.yml b/roles/execution_environments/meta/argument_specs.yml
index e8415a45f..10aa99f4f 100644
--- a/roles/execution_environments/meta/argument_specs.yml
+++ b/roles/execution_environments/meta/argument_specs.yml
@@ -60,6 +60,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/execution_environments/meta/main.yml b/roles/execution_environments/meta/main.yml
index a4b64a4f5..921f946cd 100644
--- a/roles/execution_environments/meta/main.yml
+++ b/roles/execution_environments/meta/main.yml
@@ -41,7 +41,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/execution_environments/tasks/main.yml b/roles/execution_environments/tasks/main.yml
index 71e119895..fe6dc1d50 100644
--- a/roles/execution_environments/tasks/main.yml
+++ b/roles/execution_environments/tasks/main.yml
@@ -1,35 +1,44 @@
---
# Create Controller Execution Environments
-- name: Add Controller Execution Environments
+- name: "Managing Controller Execution Environments"
execution_environment:
name: "{{ __execution_environments_item.name | mandatory }}"
- description: "{{ __execution_environments_item.description | default(omit, true) }}"
+ new_name: "{{ __execution_environments_item.new_name | default(omit, true) }}"
+ description: "{{ __execution_environments_item.description | default(('' if controller_configuration_execution_environments_enforce_defaults else omit), true) }}"
image: "{{ __execution_environments_item.image | mandatory }}"
- organization: "{{ __execution_environments_item.organization.name | default(__execution_environments_item.organization | default(omit, true)) }}"
- credential: "{{ __execution_environments_item.credential | default(omit, true) }}"
- pull: "{{ __execution_environments_item.pull | default(omit, true) }}"
+ organization: "{{ __execution_environments_item.organization.name | default(__execution_environments_item.organization | default(('' if controller_configuration_execution_environments_enforce_defaults else omit), true)) }}"
+ credential: "{{ __execution_environments_item.credential | default(('' if controller_configuration_execution_environments_enforce_defaults else omit), true) }}"
+ pull: "{{ __execution_environments_item.pull | default(('missing' if controller_configuration_execution_environments_enforce_defaults else omit), true) }}"
state: "{{ __execution_environments_item.state | default(controller_state | default('present')) }}"
# Role specific options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_execution_environments }}"
+ loop: "{{ execution_environments if execution_environments is defined else controller_execution_environments }}"
loop_control:
loop_var: "__execution_environments_item"
+ label: "{{ __operation.verb }} Controller Execution Environment {{ __execution_environments_item }}"
no_log: "{{ controller_configuration_execution_environments_secure_logging }}"
when: controller_execution_environments is defined
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __execution_environments_job_async
changed_when: not __execution_environments_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__execution_environments_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Create Controller Execution Environments | Wait for finish the Controller Execution Environments creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __execution_environments_job_async.failed is defined and __execution_environments_job_async.failed
+
+- name: "Managing Controller Execution Environments | Wait for finish the Controller Execution Environments management"
ansible.builtin.async_status:
jid: "{{ __execution_environments_job_async_results_item.ansible_job_id }}"
register: __execution_environments_job_async_result
@@ -39,8 +48,10 @@
loop: "{{ __execution_environments_job_async.results }}"
loop_control:
loop_var: __execution_environments_job_async_results_item
- when: __execution_environments_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Execution Environment {{ __execution_environments_job_async_results_item.__execution_environments_item.name }} | Wait for finish the Controller Execution Environment {{ __operation.action }}"
+ when: not ansible_check_mode and __execution_environments_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_execution_environments_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__execution_environments_job_async_results_item.__execution_environments_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/filetree_create/README.md b/roles/filetree_create/README.md
index f84c5f150..893d30190 100644
--- a/roles/filetree_create/README.md
+++ b/roles/filetree_create/README.md
@@ -15,8 +15,11 @@ The following variables are required for that role to work properly:
| Variable Name | Default Value | Required | Type | Description |
| :------------ | :-----------: | :------: | :------: | :---------- |
| `controller_api_plugin` | `ansible.controller` | yes | str | Full path for the controller_api_plugin to be used.
Can have two possible values:
- awx.awx.controller_api # For the community Collection version
- ansible.controller.controller_api # For the Red Hat Certified Collection version|
+| `organization_filter` | N/A | no | str | Exports only the objects belonging to the specified organization (applies to all the objects that can be assigned to an organization). |
+| `organization_id` | N/A | no | int | Alternative to `organization_filter`, but specifiying the current organization's ID to filter by. Exports only the objects belonging to the specified organization (applies to all the objects that can be assigned to an organization). |
| `output_path` | `/tmp/filetree_output` | yes | str | The path to the output directory where all the generated `yaml` files with the corresponding Objects as code will be written to. |
-| `input_tag` | `['all']` | no | bool | The tags which are applied to the 'sub-roles'. If 'all' is in the list (the default value) then all roles will be called. |
+| `input_tag` | `['all']` | no | List of Strings | The tags which are applied to the 'sub-roles'. If 'all' is in the list (the default value) then all roles will be called. |
+| `flatten_output` | N/A | no | bool | Whether to flatten the output in single files per each object type instead of the normal exportation structure |
## Dependencies
@@ -76,6 +79,122 @@ A list of other roles hosted on Galaxy should go here, plus any details in regar
...
```
+This role can generate output files in two different ways:
+
+- **Structured output**:
+
+ The output files are distributed in separate directories, by organization first, and then by object type. Into each of these directories, one file per object is generated. This way allows to organize the files using different criteria, for example, by funcionalities or applications.
+
+ The expotation can be triggered with the following command:
+
+ ```console
+ ansible-playbook -i localhost, filetree_create.yml -e '{controller_validate_certs: false, controller_hostname: localhost:8443, controller_username: admin, controller_password: password}'
+ ```
+
+ One example of this approach follows:
+
+ ```console
+ /tmp/filetree_output_distributted
+ ├── current_credential_types.yaml
+ ├── current_execution_environments.yaml
+ ├── current_instance_groups.yaml
+ ├── current_settings.yaml
+ ├── Default
+ │  ├── applications
+ │  │  ├── 23_controller_application-app2.yaml
+ │  │  └── 24_controller_application-app3.yaml
+ │  ├── credentials
+ │  │  ├── 82_Demo Credential.yaml
+ │  │  └── 84_Demo Custom Credential.yaml
+ │  ├── current_organization.yaml
+ │  ├── inventories
+ │  │  ├── Demo Inventory
+ │  │  │  └── 81_Demo Inventory.yaml
+ │  │  └── Test Inventory - Smart
+ │  │  ├── 78_Test Inventory - Smart.yaml
+ │  │  └── current_hosts.yaml
+ │  ├── job_templates
+ │  │  ├── 177_test-template-1.yaml
+ │  │  └── 190_Demo Job Template.yaml
+ │  ├── labels
+ │  │  ├── 52_Prod.yaml
+ │  │  ├── 53_differential.yaml
+ │  ├── notification_templates
+ │  │  ├── Email notification differential.yaml
+ │  │  └── Email notification.yaml
+ │  ├── projects
+ │  │  ├── 169_Test Project.yaml
+ │  │  ├── 170_Demo Project.yaml
+ │  ├── teams
+ │  │  ├── 28_satellite-qe.yaml
+ │  │  └── 29_tower-team.yaml
+ │  └── workflow_job_templates
+ │  ├── 191_Simple workflow schema.yaml
+ │  └── 200_Complicated workflow schema.yaml
+ ├── ORGANIZATIONLESS
+ │  ├── credentials
+ │  │  ├── 2_Ansible Galaxy.yaml
+ │  │  └── 3_Default Execution Environment Registry Credential.yaml
+ │  └── users
+ │  ├── admin.yaml
+ │  ├── controller_user.yaml
+ ├── schedules
+ │  ├── 1_Cleanup Job Schedule.yaml
+ │  ├── 2_Cleanup Activity Schedule.yaml
+ │  ├── 4_Cleanup Expired Sessions.yaml
+ │  ├── 52_Demo Schedule.yaml
+ │  ├── 53_Demo Schedule 2.yaml
+ │  └── 5_Cleanup Expired OAuth 2 Tokens.yaml
+ ├── team_roles
+ │  ├── current_roles_satellite-qe.yaml
+ │  └── current_roles_tower-team.yaml
+ └── user_roles
+ └── current_roles_controller_user.yaml
+ ```
+
+- **Flatten files**:
+
+ The output files are all located in the same directory. Each file contains a YAML list with all the objects belonging to the same object type. This output format allows to load all the objects both from the standard Ansible `group_vars` and from the `infra.controller_configuration.filetree_read` role.
+
+ The expotation can be triggered with the following command:
+
+ ```console
+ ansible-playbook -i localhost, filetree_create.yml -e '{controller_validate_certs: false, controller_hostname: localhost:8443, controller_username: admin, controller_password: password, flatten_output: true}'
+ ```
+
+ One example of this approach follows:
+
+ ```console
+ /tmp/filetree_output_flatten
+ ├── applications.yaml
+ ├── credentials.yaml
+ ├── current_credential_types.yaml
+ ├── current_execution_environments.yaml
+ ├── current_instance_groups.yaml
+ ├── current_settings.yaml
+ ├── groups.yaml
+ ├── hosts.yaml
+ ├── inventories.yaml
+ ├── inventory_sources.yaml
+ ├── job_templates.yaml
+ ├── labels.yaml
+ ├── notification_templates.yaml
+ ├── organizations.yaml
+ ├── projects.yaml
+ ├── schedules.yaml
+ ├── team_roles.yaml
+ ├── teams.yaml
+ ├── user_roles.yaml
+ ├── users.yaml
+ └── workflow_job_templates.yaml
+ ```
+
+A playbook to convert from the structured output to the flattened one is provided, and can be executed with the following command:
+
+```console
+ansible-playbook infra.controller_configuration.flatten_filetree_create_output.yaml -e '{filetree_create_output_dir: /tmp/filetree_output}'
+```
+
## License
GPLv3+
diff --git a/roles/filetree_create/tasks/all.yml b/roles/filetree_create/tasks/all.yml
index 900038000..b3059bd6d 100644
--- a/roles/filetree_create/tasks/all.yml
+++ b/roles/filetree_create/tasks/all.yml
@@ -6,12 +6,33 @@
verify_ssl=controller_validate_certs).version is version('4.0.0', '>=') }}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+- name: "Block to get the organization_filter ID to filter all the queries"
+ when:
+ - organization_filter is defined
+ - organization_filter | length > 0
+ block:
+ - name: "Get the organization_filter ID to restrict the API queries"
+ ansible.builtin.set_fact:
+ organization_id: "{{ lookup(controller_api_plugin, 'organizations',
+ query_params={'name': organization_filter},
+ host=controller_hostname, oauth_token=controller_oauthtoken,
+ verify_ssl=controller_validate_certs).id
+ }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+
+ - name: "Show the organization_filter ID"
+ ansible.builtin.debug:
+ msg: "The organization {{ organization_filter }} has the ID {{ organization_id }}"
+
- name: Include tasks (block)
- when: "['all', 'labels', 'applications', 'instance_groups', 'settings', 'inventory', 'credentials', 'credential_types', 'notification_templates', 'users', 'teams', 'organizations', 'projects', 'execution_environments', 'job_templates', 'workflow_job_templates', 'workflow_job_template_nodes'] | intersect(input_tag) | length > 0"
+ when: "['all', 'labels', 'applications', 'instance_groups', 'settings', 'inventory', 'credentials', 'credential_types', 'notification_templates', 'users', 'teams', 'roles', 'organizations', 'projects', 'execution_environments', 'job_templates', 'workflow_job_templates', 'workflow_job_template_nodes', 'schedules'] | intersect(input_tag) | length > 0"
block:
- name: "Export Inventories and related Groups and Hosts"
ansible.builtin.include_tasks: "inventory.yml"
when: "'inventory' in input_tag or 'all' in input_tag"
+ - name: "Export Constructed Inventories"
+ ansible.builtin.include_tasks: "constructed_inventory.yml"
+ when: "'inventory' in input_tag or 'all' in input_tag"
- name: "Export Credentials"
ansible.builtin.include_tasks: "credentials.yml"
when: "'credentials' in input_tag or 'all' in input_tag"
@@ -23,10 +44,10 @@
when: "'notification_templates' in input_tag or 'all' in input_tag"
- name: "Export Users"
ansible.builtin.include_tasks: "users.yml"
- when: "'users' in input_tag or 'all' in input_tag"
+ when: "'users' in input_tag or 'roles' in input_tag or 'all' in input_tag"
- name: "Export Teams"
ansible.builtin.include_tasks: "teams.yml"
- when: "'teams' in input_tag or 'all' in input_tag"
+ when: "'teams' in input_tag or 'roles' in input_tag or 'all' in input_tag"
- name: "Export Organizations"
ansible.builtin.include_tasks: "organizations.yml"
when: "'organizations' in input_tag or 'all' in input_tag"
@@ -54,4 +75,7 @@
- name: "Export Labels"
ansible.builtin.include_tasks: "labels.yml"
when: "'labels' in input_tag or 'all' in input_tag"
+ - name: "Export Schedules"
+ ansible.builtin.include_tasks: "schedules.yml"
+ when: "'schedules' in input_tag or 'all' in input_tag"
...
diff --git a/roles/filetree_create/tasks/applications.yml b/roles/filetree_create/tasks/applications.yml
index 477902b17..1d8b7a9c9 100644
--- a/roles/filetree_create/tasks/applications.yml
+++ b/roles/filetree_create/tasks/applications.yml
@@ -1,39 +1,77 @@
---
- name: "Get current Applications from the API"
ansible.builtin.set_fact:
- applications_lookvar: "{{ query(controller_api_plugin, 'api/v2/applications/',
- query_params={'order_by': 'organization,id'},
+ applications_lookvar: "{{ query(controller_api_plugin, 'applications/',
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /applications output directory for applications in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/applications"
- loop: "{{ (applications_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((applications_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/applications.yaml"
+ block:
+ - name: "Add current applications to the applications flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_applications.j2') }}"
+ vars:
+ application_organization: "{{ current_applications_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ application_id: "{{ current_applications_asset_value.id }}"
+ application_name: "{{ current_applications_asset_value.name | regex_replace('/', '_') }}"
+ last_application: "{{ current_application_index == ((applications_lookvar | length) - 1) }}"
+ loop: "{{ applications_lookvar }}"
+ loop_control:
+ index_var: current_application_index
+ loop_var: current_applications_asset_value
+ label: "{{ __dest }}"
-- name: "Add current applications to the /applications output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_applications.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- application_organization: "{{ current_applications_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
- application_id: "{{ current_applications_asset_value.id }}"
- application_name: "{{ current_applications_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ application_organization | regex_replace('/', '_') }}/applications/{{ application_id }}_{{ application_name | regex_replace('/', '_') }}.yaml"
- loop: "{{ applications_lookvar }}"
- loop_control:
- loop_var: current_applications_asset_value
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /applications output directory for applications in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/applications"
+ loop: "{{ (applications_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((applications_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current applications to the /applications output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_applications.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ application_organization: "{{ current_applications_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ application_id: "{{ current_applications_asset_value.id }}"
+ application_name: "{{ current_applications_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ application_organization | regex_replace('/', '_') }}/applications/{{ application_id }}_{{ application_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ applications_lookvar }}"
+ loop_control:
+ loop_var: current_applications_asset_value
+ label: "{{ __dest }}"
...
diff --git a/roles/filetree_create/tasks/constructed_inventory.yml b/roles/filetree_create/tasks/constructed_inventory.yml
new file mode 100644
index 000000000..fdee02e91
--- /dev/null
+++ b/roles/filetree_create/tasks/constructed_inventory.yml
@@ -0,0 +1,88 @@
+---
+- name: "Get the constructed inventories from the API"
+ ansible.builtin.set_fact:
+ constructed_inventory_lookvar: "{{ query(controller_api_plugin, 'api/v2/constructed_inventories/',
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
+ vars:
+ __dest: "{{ output_path }}/inventories.yaml"
+ block:
+ - name: "Stat if the output file exists"
+ ansible.builtin.stat:
+ path: "{{ __dest }}"
+ register: __constructed_inventories_file
+
+ - name: "Remove the yaml finalizer if it's already present"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: "..."
+ state: absent
+ when: __constructed_inventories_file.stat.exists | bool
+
+ - name: "Add current constructed inventory to the inventories flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_inventories.j2') }}"
+ vars:
+ inventory_organization: "{{ current_inventories_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ current_inventories_asset_value.name | regex_replace('/', '_') }}"
+ first_inventory: "{{ not (__constructed_inventories_file.stat.exists | bool) }}"
+ last_inventory: "{{ current_inventory_index == ((constructed_inventory_lookvar | length) - 1) }}"
+ loop: "{{ constructed_inventory_lookvar }}"
+ loop_control:
+ index_var: current_inventory_index
+ loop_var: current_inventories_asset_value
+ label: "{{ __dest }}"
+
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /inventories output directory for inventories in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ inventory_organization: "{{ needed_path.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ needed_path.name | regex_replace('/', '_') }}"
+ __path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
+ loop: "{{ constructed_inventory_lookvar }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current constructed_inventories to the /inventories output yaml file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_inventories.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ inventory_organization: "{{ current_inventories_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ current_inventories_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}/{{ current_inventories_asset_value.id }}_{{ inventory_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ constructed_inventory_lookvar }}"
+ loop_control:
+ loop_var: current_inventories_asset_value
+ label: "{{ __dest }}"
+...
diff --git a/roles/filetree_create/tasks/credentials.yml b/roles/filetree_create/tasks/credentials.yml
index 3af85f91f..97e27b956 100644
--- a/roles/filetree_create/tasks/credentials.yml
+++ b/roles/filetree_create/tasks/credentials.yml
@@ -2,38 +2,76 @@
- name: "Get current Credentials from the API"
ansible.builtin.set_fact:
credentials_lookvar: "{{ query(controller_api_plugin, 'api/v2/credentials/',
- query_params={'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /credentials output directory for credentials in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path }}/credentials"
- loop: "{{ (credentials_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((credentials_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/credentials.yaml"
+ block:
+ - name: "Add current credentials to the credentials flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_credentials.j2') }}"
+ vars:
+ credentials_organization: "{{ current_credentials_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ credentials_id: "{{ current_credentials_asset_value.id }}"
+ credentials_name: "{{ current_credentials_asset_value.name | regex_replace('/', '_') }}"
+ last_credential: "{{ current_credential_index == ((credentials_lookvar | length) - 1) }}"
+ loop: "{{ credentials_lookvar }}"
+ loop_control:
+ index_var: current_credential_index
+ loop_var: current_credentials_asset_value
+ label: "{{ __dest }}"
-- name: "Add current credentials to the /credentials output yaml file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_credentials.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- credentials_organization: "{{ current_credentials_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
- credentials_id: "{{ current_credentials_asset_value.id }}"
- credentials_name: "{{ current_credentials_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ credentials_organization | regex_replace('/', '_') }}/credentials/{{ credentials_id }}_{{ credentials_name | regex_replace('/', '_') }}.yaml"
- loop: "{{ credentials_lookvar }}"
- loop_control:
- loop_var: current_credentials_asset_value
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /credentials output directory for credentials in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path }}/credentials"
+ loop: "{{ (credentials_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((credentials_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current credentials to the /credentials output yaml file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_credentials.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ credentials_organization: "{{ current_credentials_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ credentials_id: "{{ current_credentials_asset_value.id }}"
+ credentials_name: "{{ current_credentials_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ credentials_organization | regex_replace('/', '_') }}/credentials/{{ credentials_id }}_{{ credentials_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ credentials_lookvar }}"
+ loop_control:
+ loop_var: current_credentials_asset_value
+ label: "{{ __dest }}"
...
diff --git a/roles/filetree_create/tasks/execution_environments.yml b/roles/filetree_create/tasks/execution_environments.yml
index 2fc737d3f..55d4118d7 100644
--- a/roles/filetree_create/tasks/execution_environments.yml
+++ b/roles/filetree_create/tasks/execution_environments.yml
@@ -2,9 +2,13 @@
- name: "Get current Execution Environments from the API"
ansible.builtin.set_fact:
execution_environments_lookvar: "{{ query(controller_api_plugin, 'api/v2/execution_environments/',
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
- name: "Create the output directory for execution environments: {{ output_path }}"
diff --git a/roles/filetree_create/tasks/groups.yml b/roles/filetree_create/tasks/groups.yml
index 529e605b3..cec0dbfb7 100644
--- a/roles/filetree_create/tasks/groups.yml
+++ b/roles/filetree_create/tasks/groups.yml
@@ -1,14 +1,39 @@
---
-- name: "Create the output directory for groups: {{ groups_output_path }}"
- ansible.builtin.file:
- path: "{{ groups_output_path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
+ vars:
+ __dest: "{{ groups_output_path }}"
+ block:
+ - name: "Add current groups to the groups flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_groups.j2') }}"
-- name: "Add current groups to the current_groups.yaml output file in {{ groups_output_path }}"
- ansible.builtin.template:
- src: "templates/current_groups.j2"
- dest: "{{ groups_output_path }}/current_groups.yaml"
- mode: '0644'
- when: current_groups_asset_value | length > 0
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for groups: {{ groups_output_path }}"
+ ansible.builtin.file:
+ path: "{{ groups_output_path }}"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current groups to the current_groups.yaml output file in {{ groups_output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_groups.j2"
+ dest: "{{ groups_output_path }}/current_groups.yaml"
+ mode: '0644'
+ when: current_groups_asset_value | length > 0
...
diff --git a/roles/filetree_create/tasks/hosts.yml b/roles/filetree_create/tasks/hosts.yml
index 8ef5a38f5..514929fcf 100644
--- a/roles/filetree_create/tasks/hosts.yml
+++ b/roles/filetree_create/tasks/hosts.yml
@@ -1,14 +1,39 @@
---
-- name: "Create the output directory for hosts: {{ hosts_output_path }}"
- ansible.builtin.file:
- path: "{{ hosts_output_path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
+ vars:
+ __dest: "{{ hosts_output_path }}"
+ block:
+ - name: "Add current hosts to the hosts flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_hosts.j2') }}"
-- name: "Add current hosts to the current_hosts.yaml output file in {{ hosts_output_path }}"
- ansible.builtin.template:
- src: "templates/current_hosts.j2"
- dest: "{{ hosts_output_path }}/current_hosts.yaml"
- mode: '0644'
- when: current_hosts_asset_value | length > 0
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for hosts: {{ hosts_output_path }}"
+ ansible.builtin.file:
+ path: "{{ hosts_output_path }}"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current hosts to the current_hosts.yaml output file in {{ hosts_output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_hosts.j2"
+ dest: "{{ hosts_output_path }}/current_hosts.yaml"
+ mode: '0644'
+ when: current_hosts_asset_value | length > 0
...
diff --git a/roles/filetree_create/tasks/inventory.yml b/roles/filetree_create/tasks/inventory.yml
index 2c3e9ef64..fd05db1f9 100644
--- a/roles/filetree_create/tasks/inventory.yml
+++ b/roles/filetree_create/tasks/inventory.yml
@@ -2,53 +2,109 @@
- name: "Get the inventories from the API"
ansible.builtin.set_fact:
inventory_lookvar: "{{ query(controller_api_plugin, 'api/v2/inventories/',
- query_params={'not__kind': 'smart', 'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ not__kind: 'constructed'
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /inventories output directory for inventories in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- inventory_organization: "{{ needed_path.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
- inventory_name: "{{ needed_path.name | regex_replace('/', '_') }}"
- __path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
- loop: "{{ inventory_lookvar }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/inventories.yaml"
+ block:
+ - name: "Stat if the output file exists"
+ ansible.builtin.stat:
+ path: "{{ __dest }}"
+ register: __inventories_file
-- name: "Add current inventories to the /inventories output yaml file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_inventories.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- inventory_organization: "{{ current_inventories_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
- inventory_name: "{{ current_inventories_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}/{{ current_inventories_asset_value.id }}_{{ inventory_name | regex_replace('/', '_') }}.yaml"
- loop: "{{ inventory_lookvar }}"
- loop_control:
- loop_var: current_inventories_asset_value
- label: "{{ __dest }}"
+ - name: "Remove the yaml finalizer if it's already present"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: "..."
+ state: absent
+ when: __inventories_file.stat.exists | bool
+
+ - name: "Add current inventories to the inventories flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ''
+ block: "{{ lookup('template', 'templates/current_inventories.j2') }}"
+ vars:
+ inventory_organization: "{{ current_inventories_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ current_inventories_asset_value.name | regex_replace('/', '_') }}"
+ first_inventory: "{{ not (__inventories_file.stat.exists | bool) }}"
+ last_inventory: "{{ current_inventory_index == ((inventory_lookvar | length) - 1) }}"
+ loop: "{{ inventory_lookvar }}"
+ loop_control:
+ index_var: current_inventory_index
+ loop_var: current_inventories_asset_value
+ label: "{{ __dest }}"
+
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /inventories output directory for inventories in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ inventory_organization: "{{ needed_path.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ needed_path.name | regex_replace('/', '_') }}"
+ __path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
+ loop: "{{ inventory_lookvar }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current inventories to the /inventories output yaml file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_inventories.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ inventory_organization: "{{ current_inventories_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ inventory_name: "{{ current_inventories_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}/{{ current_inventories_asset_value.id }}_{{ inventory_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ inventory_lookvar }}"
+ loop_control:
+ loop_var: current_inventories_asset_value
+ label: "{{ __dest }}"
- name: "Set the inventory's inventory sources"
ansible.builtin.include_tasks: "inventory_sources.yml"
vars:
inventory_organization: "{{ current_inventory_sources.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
inventory_name: "{{ current_inventory_sources.name | regex_replace('/', '_') }}"
- inventory_sources_output_path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
+ inventory_sources_output_path: "{{ (output_path + '/' + inventory_organization | regex_replace('/', '_') + '/inventories/' + inventory_name | regex_replace('/', '_'))
+ if (flatten_output is not defined or (flatten_output | bool) == false)
+ else
+ output_path + '/inventory_sources.yaml' }}"
current_inventory_sources_asset_value: "{{ query(controller_api_plugin, current_inventory_sources.related.inventory_sources,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
if current_inventory_sources.has_inventory_sources else []
}}"
+ last_inventory: "{{ current_inventory_index == ((inventory_lookvar | length) - 1) }}"
loop: "{{ inventory_lookvar }}"
loop_control:
+ index_var: current_inventory_index
loop_var: current_inventory_sources
label: "{{ inventory_sources_output_path }}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
@@ -58,31 +114,44 @@
vars:
inventory_organization: "{{ current_inventory_hosts.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
inventory_name: "{{ current_inventory_hosts.name | regex_replace('/', '_') }}"
- hosts_output_path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
+ hosts_output_path: "{{ (output_path + '/' + inventory_organization | regex_replace('/', '_') + '/inventories/' + inventory_name | regex_replace('/', '_'))
+ if (flatten_output is not defined or (flatten_output | bool) == false)
+ else
+ output_path + '/hosts.yaml' }}"
current_hosts_asset_value: "{{ query(controller_api_plugin, current_inventory_hosts.related.hosts,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- if not current_inventory_hosts.has_inventory_sources else []
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ if not current_inventory_hosts.has_inventory_sources else []
}}"
+ first_inventory: "{{ not (__inventories_file.stat.exists | bool) }}"
+ last_inventory: "{{ current_inventory_index == ((inventory_lookvar | length) - 1) }}"
loop: "{{ inventory_lookvar }}"
loop_control:
+ index_var: current_inventory_index
loop_var: current_inventory_hosts
label: "{{ hosts_output_path }}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
- name: "Set the inventory's groups"
ansible.builtin.include_tasks: "groups.yml"
+ when: current_inventory_groups.total_groups > 0
vars:
inventory_organization: "{{ current_inventory_groups.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
inventory_name: "{{ current_inventory_groups.name | regex_replace('/', '_') }}"
- groups_output_path: "{{ output_path }}/{{ inventory_organization | regex_replace('/', '_') }}/inventories/{{ inventory_name | regex_replace('/', '_') }}"
+ groups_output_path: "{{ (output_path + '/' + inventory_organization | regex_replace('/', '_') + '/inventories/' + inventory_name | regex_replace('/', '_'))
+ if (flatten_output is not defined or (flatten_output | bool) == false)
+ else
+ output_path + '/groups.yaml' }}"
current_groups_asset_value: "{{ query(controller_api_plugin, current_inventory_groups.related.groups,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- if not current_inventory_groups.has_inventory_sources else []
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ if (not current_inventory_groups.has_inventory_sources or current_inventory_groups.kind is match('smart')) else []
}}"
+ first_inventory: "{{ not (__inventories_file.stat.exists | bool) }}"
+ last_inventory: "{{ current_inventory_index == ((inventory_lookvar | length) - 1) }}"
loop: "{{ inventory_lookvar }}"
loop_control:
+ index_var: current_inventory_index
loop_var: current_inventory_groups
label: "{{ groups_output_path }}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
diff --git a/roles/filetree_create/tasks/inventory_sources.yml b/roles/filetree_create/tasks/inventory_sources.yml
index fa09b1595..0c67ca6cf 100644
--- a/roles/filetree_create/tasks/inventory_sources.yml
+++ b/roles/filetree_create/tasks/inventory_sources.yml
@@ -1,14 +1,40 @@
---
-- name: "Create the output directory for inventory sources: {{ inventory_sources_output_path }}"
- ansible.builtin.file:
- path: "{{ inventory_sources_output_path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
+ block:
+ - name: "Add current inventory source to the inventory sources flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ inventory_sources_output_path }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_inventory_sources.j2') }}"
+ vars:
+ last_inventory: "{{ current_inventory_for_sources_index == ((inventory_lookvar | length) - 1) }}"
-- name: "Add current inventory source to the current_inventory_sources.yaml output file in {{ inventory_sources_output_path }}"
- ansible.builtin.template:
- src: "templates/current_inventory_sources.j2"
- dest: "{{ inventory_sources_output_path }}/current_inventory_sources.yaml"
- mode: '0644'
- when: current_inventory_sources_asset_value | length > 0
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ inventory_sources_output_path }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for inventory sources: {{ inventory_sources_output_path }}"
+ ansible.builtin.file:
+ path: "{{ inventory_sources_output_path }}"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current inventory source to the current_inventory_sources.yaml output file in {{ inventory_sources_output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_inventory_sources.j2"
+ dest: "{{ inventory_sources_output_path }}/current_inventory_sources.yaml"
+ mode: '0644'
+ when:
+ - current_inventory_sources_asset_value | length > 0
...
diff --git a/roles/filetree_create/tasks/job_templates.yml b/roles/filetree_create/tasks/job_templates.yml
index 87617eaf1..90f7076bf 100644
--- a/roles/filetree_create/tasks/job_templates.yml
+++ b/roles/filetree_create/tasks/job_templates.yml
@@ -2,51 +2,102 @@
- name: "Get current Job Templates from the API"
ansible.builtin.set_fact:
job_templates_lookvar: "{{ query(controller_api_plugin, 'api/v2/job_templates/',
- query_params={'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the output directories for job templates in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/job_templates"
- loop: "{{ (job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/job_templates.yaml"
+ block:
+ - name: "Add current job_templates to the job_templates flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_job_templates.j2') }}"
+ vars:
+ job_template_organization: "{{ current_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ job_template_id: "{{ current_job_templates_asset_value.id }}"
+ job_template_name: "{{ current_job_templates_asset_value.name | regex_replace('/', '_') }}"
+ query_labels: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_error: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ last_job_template: "{{ current_job_template_index == ((job_templates_lookvar | length) - 1) }}"
+ loop: "{{ job_templates_lookvar }}"
+ loop_control:
+ index_var: current_job_template_index
+ loop_var: current_job_templates_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Add current job_templates to the /job_templates output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_job_templates.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- job_template_organization: "{{ current_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
- job_template_id: "{{ current_job_templates_asset_value.id }}"
- job_template_name: "{{ current_job_templates_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ job_template_organization | regex_replace('/', '_') }}/job_templates/{{ job_template_id }}_{{ job_template_name | regex_replace('/', '_') }}.yaml"
- query_labels: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.labels,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_error: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_error,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_started: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_started,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_success: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_success,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- loop: "{{ job_templates_lookvar }}"
- loop_control:
- loop_var: current_job_templates_asset_value
- label: "{{ __dest }}"
- no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directories for job templates in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/job_templates"
+ loop: "{{ (job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current job_templates to the /job_templates output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_job_templates.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ job_template_organization: "{{ current_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ job_template_id: "{{ current_job_templates_asset_value.id }}"
+ job_template_name: "{{ current_job_templates_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ job_template_organization | regex_replace('/', '_') }}/job_templates/{{ job_template_id }}_{{ job_template_name | regex_replace('/', '_') }}.yaml"
+ query_labels: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_error: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_job_templates_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ loop: "{{ job_templates_lookvar }}"
+ loop_control:
+ loop_var: current_job_templates_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
...
diff --git a/roles/filetree_create/tasks/labels.yml b/roles/filetree_create/tasks/labels.yml
index f993c998f..d54144e74 100644
--- a/roles/filetree_create/tasks/labels.yml
+++ b/roles/filetree_create/tasks/labels.yml
@@ -2,38 +2,76 @@
- name: "Get current Labels from the API"
ansible.builtin.set_fact:
labels_lookvar: "{{ query(controller_api_plugin, 'api/v2/labels/',
- query_params={'order_by': 'organization,id'},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /labels output directory for labels in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/labels"
- loop: "{{ (labels_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((labels_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/labels.yaml"
+ block:
+ - name: "Add current labels to the labels flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_labels.j2') }}"
+ vars:
+ label_organization: "{{ current_labels_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ label_id: "{{ current_labels_asset_value.id }}"
+ label_name: "{{ current_labels_asset_value.name | regex_replace('/', '_') }}"
+ last_label: "{{ current_label_index == ((labels_lookvar | length) - 1) }}"
+ loop: "{{ labels_lookvar }}"
+ loop_control:
+ index_var: current_label_index
+ loop_var: current_labels_asset_value
+ label: "{{ __dest }}"
-- name: "Add current labels to the /labels output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_labels.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- label_organization: "{{ current_labels_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
- label_id: "{{ current_labels_asset_value.id }}"
- label_name: "{{ current_labels_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ label_organization | regex_replace('/', '_') }}/labels/{{ label_id }}_{{ label_name | regex_replace('/', '_') }}.yaml"
- loop: "{{ labels_lookvar }}"
- loop_control:
- loop_var: current_labels_asset_value
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /labels output directory for labels in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/labels"
+ loop: "{{ (labels_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((labels_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current labels to the /labels output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_labels.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ label_organization: "{{ current_labels_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ label_id: "{{ current_labels_asset_value.id }}"
+ label_name: "{{ current_labels_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ label_organization | regex_replace('/', '_') }}/labels/{{ label_id }}_{{ label_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ labels_lookvar }}"
+ loop_control:
+ loop_var: current_labels_asset_value
+ label: "{{ __dest }}"
...
diff --git a/roles/filetree_create/tasks/main.yml b/roles/filetree_create/tasks/main.yml
index 35fe4cd84..4241dcd23 100644
--- a/roles/filetree_create/tasks/main.yml
+++ b/roles/filetree_create/tasks/main.yml
@@ -51,4 +51,8 @@
apply:
tags: "{{ input_tag | to_yaml }}"
tags: "{{ valid_tags }}"
+
+- name: "Remind to check all the 'ToDo:' entries in the output files"
+ ansible.builtin.debug:
+ msg: "Please, check the existance of 'ToDo: ' entries in the files generated at '{{ output_path }}' with the following command: grep -R 'ToDo: ' '{{ output_path }}'"
...
diff --git a/roles/filetree_create/tasks/notification_templates.yml b/roles/filetree_create/tasks/notification_templates.yml
index d2517e90f..5aa2da2d9 100644
--- a/roles/filetree_create/tasks/notification_templates.yml
+++ b/roles/filetree_create/tasks/notification_templates.yml
@@ -2,34 +2,70 @@
- name: "Get current Notification Templates from the API"
ansible.builtin.set_fact:
notification_templates_lookvar: "{{ query(controller_api_plugin, 'api/v2/notification_templates/',
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /notification_templates output directory for notification templates in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/notification_templates"
- loop: "{{ (notification_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((notification_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/notification_templates.yaml"
+ block:
+ - name: "Add current notification_templates to the notification_templates flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_notification_templates.j2') }}"
+ vars:
+ last_notification_template: "{{ current_notification_template_index == ((notification_templates_lookvar | length) - 1) }}"
+ loop: "{{ notification_templates_lookvar }}"
+ loop_control:
+ index_var: current_notification_template_index
+ loop_var: current_notification_templates_asset_value
+ label: "{{ __dest }}"
-- name: "Add current notification templates to the /current_notification_templates.yaml output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_notification_templates.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- __dest: "{{ output_path }}/{{ (current_notification_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}/notification_templates/{{ current_notification_templates_asset_value.name | regex_replace('/', '_') }}.yaml"
- loop: "{{ notification_templates_lookvar }}"
- loop_control:
- loop_var: current_notification_templates_asset_value
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /notification_templates output directory for notification templates in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/notification_templates"
+ loop: "{{ (notification_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((notification_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current notification templates to the /current_notification_templates.yaml output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_notification_templates.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ __dest: "{{ output_path }}/{{ (current_notification_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}/notification_templates/{{ current_notification_templates_asset_value.name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ notification_templates_lookvar }}"
+ loop_control:
+ loop_var: current_notification_templates_asset_value
+ label: "{{ __dest }}"
...
diff --git a/roles/filetree_create/tasks/organizations.yml b/roles/filetree_create/tasks/organizations.yml
index ebbfed93c..f2de44b6f 100644
--- a/roles/filetree_create/tasks/organizations.yml
+++ b/roles/filetree_create/tasks/organizations.yml
@@ -2,46 +2,94 @@
- name: "Get current Organizations from the API"
ansible.builtin.set_fact:
orgs_lookvar: "{{ query(controller_api_plugin, 'api/v2/organizations/',
- query_params={'order_by': 'id'},
+ query_params=(query_params | combine({'id': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the output directory for organizations: {{ output_path + '/' + current_organization_dir.name }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ current_organization_dir.name | regex_replace('/', '_') }}"
- loop: "{{ orgs_lookvar }}"
- loop_control:
- loop_var: current_organization_dir
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/organizations.yaml"
+ block:
+ - name: "Add current organizations to the organizations flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_organizations.j2') }}"
+ vars:
+ query_notification_error: "{{ query(controller_api_plugin, current_organization.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_organization.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_organization.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_approvals: "{{ query(controller_api_plugin, current_organization.related.notification_templates_approvals,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ last_organization: "{{ current_organization_index == ((orgs_lookvar | length) - 1) }}"
+ loop: "{{ orgs_lookvar }}"
+ loop_control:
+ index_var: current_organization_index
+ loop_var: current_organization
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Add current organizations to the output yaml file"
- ansible.builtin.template:
- src: "templates/current_organizations.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- __dest: "{{ output_path }}/{{ current_organization.name | regex_replace('/', '_') }}/current_organization.yaml"
- query_notification_error: "{{ query(controller_api_plugin, current_organization.related.notification_templates_error,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_started: "{{ query(controller_api_plugin, current_organization.related.notification_templates_started,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_success: "{{ query(controller_api_plugin, current_organization.related.notification_templates_success,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_approvals: "{{ query(controller_api_plugin, current_organization.related.notification_templates_approvals,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- loop: "{{ orgs_lookvar }}"
- loop_control:
- loop_var: current_organization
- label: "{{ __dest }}"
- no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for organizations: {{ output_path + '/' + current_organization_dir.name }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ current_organization_dir.name | regex_replace('/', '_') }}"
+ loop: "{{ orgs_lookvar }}"
+ loop_control:
+ loop_var: current_organization_dir
+ label: "{{ __path }}"
+
+ - name: "Add current organizations to the output yaml file"
+ ansible.builtin.template:
+ src: "templates/current_organizations.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ __dest: "{{ output_path }}/{{ current_organization.name | regex_replace('/', '_') }}/current_organization.yaml"
+ query_notification_error: "{{ query(controller_api_plugin, current_organization.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_organization.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_organization.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_approvals: "{{ query(controller_api_plugin, current_organization.related.notification_templates_approvals,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ loop: "{{ orgs_lookvar }}"
+ loop_control:
+ loop_var: current_organization
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
...
diff --git a/roles/filetree_create/tasks/projects.yml b/roles/filetree_create/tasks/projects.yml
index 0b96f126d..4cf7a838b 100644
--- a/roles/filetree_create/tasks/projects.yml
+++ b/roles/filetree_create/tasks/projects.yml
@@ -2,48 +2,96 @@
- name: "Get current Projects from the API"
ansible.builtin.set_fact:
projects_lookvar: "{{ query(controller_api_plugin, 'api/v2/projects/',
- query_params={'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /projects output directory for projects in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/projects"
- loop: "{{ (projects_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((projects_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/projects.yaml"
+ block:
+ - name: "Add current projects to the projects flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_projects.j2') }}"
+ vars:
+ project_organization: "{{ current_projects_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ project_id: "{{ current_projects_asset_value.id }}"
+ project_name: "{{ current_projects_asset_value.name | regex_replace('/', '_') }}"
+ query_notification_error: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ last_project: "{{ current_project_index == ((projects_lookvar | length) - 1) }}"
+ loop: "{{ projects_lookvar }}"
+ loop_control:
+ index_var: current_project_index
+ loop_var: current_projects_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Add current projects to the /projects output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_projects.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- project_organization: "{{ current_projects_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
- project_id: "{{ current_projects_asset_value.id }}"
- project_name: "{{ current_projects_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ project_organization | regex_replace('/', '_') }}/projects/{{ project_id }}_{{ project_name | regex_replace('/', '_') }}.yaml"
- query_notification_error: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_error,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_started: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_started,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_success: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_success,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- loop: "{{ projects_lookvar }}"
- loop_control:
- loop_var: current_projects_asset_value
- label: "{{ __dest }}"
- no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /projects output directory for projects in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/projects"
+ loop: "{{ (projects_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((projects_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current projects to the /projects output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_projects.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ project_organization: "{{ current_projects_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true) }}"
+ project_id: "{{ current_projects_asset_value.id }}"
+ project_name: "{{ current_projects_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ project_organization | regex_replace('/', '_') }}/projects/{{ project_id }}_{{ project_name | regex_replace('/', '_') }}.yaml"
+ query_notification_error: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_projects_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ loop: "{{ projects_lookvar }}"
+ loop_control:
+ loop_var: current_projects_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
...
diff --git a/roles/filetree_create/tasks/schedules.yml b/roles/filetree_create/tasks/schedules.yml
new file mode 100644
index 000000000..0fc38b364
--- /dev/null
+++ b/roles/filetree_create/tasks/schedules.yml
@@ -0,0 +1,81 @@
+---
+- name: "Get current Schedules from the API"
+ ansible.builtin.set_fact:
+ schedules_lookvar: "{{ query(controller_api_plugin, 'api/v2/schedules/',
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
+ vars:
+ __dest: "{{ output_path }}/schedules.yaml"
+ block:
+ - name: "Add current schedules to the schedules flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_schedules.j2') }}"
+ vars:
+ label_id: "{{ current_schedules_asset_value.id }}"
+ label_name: "{{ current_schedules_asset_value.name | regex_replace('/', '_') }}"
+ query_credentials: "{{ query(controller_api_plugin, current_schedules_asset_value.related.credentials,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.credentials is defined else [] }}"
+ query_instance_groups: "{{ query(controller_api_plugin, current_schedules_asset_value.related.instance_groups,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.instance_groups is defined else [] }}"
+ query_labels: "{{ query(controller_api_plugin, current_schedules_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.labels is defined else [] }}"
+ last_schedule: "{{ current_schedule_index == ((schedules_lookvar | length) - 1) }}"
+ loop: "{{ schedules_lookvar }}"
+ loop_control:
+ index_var: current_schedule_index
+ loop_var: current_schedules_asset_value
+ label: "{{ __dest }}"
+
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the schedules output directory for schedules in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ output_path }}/schedules"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current schedules to the schedules output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_schedules.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ label_id: "{{ current_schedules_asset_value.id }}"
+ label_name: "{{ current_schedules_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/schedules/{{ label_id }}_{{ label_name | regex_replace('/', '_') }}.yaml"
+ query_credentials: "{{ query(controller_api_plugin, current_schedules_asset_value.related.credentials,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.credentials is defined else [] }}"
+ query_instance_groups: "{{ query(controller_api_plugin, current_schedules_asset_value.related.instance_groups,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.instance_groups is defined else [] }}"
+ query_labels: "{{ query(controller_api_plugin, current_schedules_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) if current_schedules_asset_value.related.labels is defined else [] }}"
+ loop: "{{ schedules_lookvar }}"
+ loop_control:
+ loop_var: current_schedules_asset_value
+ label: "{{ __dest }}"
+...
diff --git a/roles/filetree_create/tasks/team_roles.yml b/roles/filetree_create/tasks/team_roles.yml
index 1db22c86d..19a003d6f 100644
--- a/roles/filetree_create/tasks/team_roles.yml
+++ b/roles/filetree_create/tasks/team_roles.yml
@@ -7,18 +7,52 @@
}}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the output directory for team roles: {{ output_path }}"
- ansible.builtin.file:
- path: "{{ output_path }}/team_roles"
- state: directory
- mode: '0755'
-
-- name: "Add current roles to the output yaml file"
- ansible.builtin.template:
- src: "templates/current_team_roles.j2"
- dest: "{{ output_path }}/team_roles/current_roles_{{ teamname | regex_replace('/', '_') }}.yaml"
- mode: '0644'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- current_team_roles_asset_value: "{{ team_roles_lookvar }}"
- when: team_roles_lookvar | length > 0
+ __dest: "{{ output_path }}/team_roles.yaml"
+ block:
+ - name: "Stat if the output file exists"
+ ansible.builtin.stat:
+ path: "{{ __dest }}"
+ register: team_roles_file
+
+ - name: "Add current team roles to the team roles flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_team_roles.j2') }}"
+ vars:
+ current_team_roles_asset_value: "{{ team_roles_lookvar }}"
+ first_team_role: "{{ not team_roles_file.stat.exists }}"
+ when: team_roles_lookvar | length > 0
+
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for team roles: {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ output_path }}/team_roles"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current roles to the output yaml file"
+ ansible.builtin.template:
+ src: "templates/current_team_roles.j2"
+ dest: "{{ output_path }}/team_roles/current_roles_{{ teamname | regex_replace('/', '_') }}.yaml"
+ mode: '0644'
+ vars:
+ current_team_roles_asset_value: "{{ team_roles_lookvar }}"
+ when: team_roles_lookvar | length > 0
...
diff --git a/roles/filetree_create/tasks/teams.yml b/roles/filetree_create/tasks/teams.yml
index ea20e6ae3..e84807768 100644
--- a/roles/filetree_create/tasks/teams.yml
+++ b/roles/filetree_create/tasks/teams.yml
@@ -2,47 +2,88 @@
- name: "Get current Teams from the API"
ansible.builtin.set_fact:
teams_lookvar: "{{ query(controller_api_plugin, 'api/v2/teams/',
- query_params={'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /teams output directory for teams in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/teams"
- loop: "{{ (teams_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((teams_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/teams.yaml"
+ block:
+ - name: "Add current teams to the teams flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_teams.j2') }}"
+ vars:
+ team_organization: "{{ (current_teams_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}"
+ team_id: "{{ current_teams_asset_value.id }}"
+ team_name: "{{ current_teams_asset_value.name | regex_replace('/', '_') }}"
+ last_team: "{{ current_team_index == ((teams_lookvar | length) - 1) }}"
+ loop: "{{ teams_lookvar }}"
+ loop_control:
+ index_var: current_team_index
+ loop_var: current_teams_asset_value
+ label: "{{ __dest }}"
-- name: "Add current teams to the /teams output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_teams.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- team_organization: "{{ (current_teams_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}"
- team_id: "{{ current_teams_asset_value.id }}"
- team_name: "{{ current_teams_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ team_organization | regex_replace('/', '_') }}/teams/{{ team_id }}_{{ team_name | regex_replace('/', '_') }}.yaml"
- loop: "{{ teams_lookvar }}"
- loop_control:
- loop_var: current_teams_asset_value
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /teams output directory for teams in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/teams"
+ loop: "{{ (teams_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((teams_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current teams to the /teams output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_teams.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ team_organization: "{{ (current_teams_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}"
+ team_id: "{{ current_teams_asset_value.id }}"
+ team_name: "{{ current_teams_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ team_organization | regex_replace('/', '_') }}/teams/{{ team_id }}_{{ team_name | regex_replace('/', '_') }}.yaml"
+ loop: "{{ teams_lookvar }}"
+ loop_control:
+ loop_var: current_teams_asset_value
+ label: "{{ __dest }}"
- name: "Set the team's roles"
ansible.builtin.include_tasks: "team_roles.yml"
vars:
+ team_organization: "{{ (current_team.summary_fields.organization.name | default('ORGANIZATIONLESS', true)) | regex_replace('/', '_') }}"
teamname: "{{ current_team.name }}"
teamid: "{{ current_team.id }}"
+ last_team_role: "{{ current_team_index_for_roles == ((teams_lookvar | length) - 1) }}"
loop: "{{ teams_lookvar }}"
loop_control:
+ index_var: current_team_index_for_roles
loop_var: current_team
...
diff --git a/roles/filetree_create/tasks/user_roles.yml b/roles/filetree_create/tasks/user_roles.yml
index cd4335327..24eab4c86 100644
--- a/roles/filetree_create/tasks/user_roles.yml
+++ b/roles/filetree_create/tasks/user_roles.yml
@@ -7,18 +7,52 @@
}}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the output directory for user roles: {{ output_path }}"
- ansible.builtin.file:
- path: "{{ output_path }}/user_roles"
- state: directory
- mode: '0755'
-
-- name: "Add current roles to the output yaml file"
- ansible.builtin.template:
- src: "templates/current_user_roles.j2"
- dest: "{{ output_path }}/user_roles/current_roles_{{ username | regex_replace('/', '_') }}.yaml"
- mode: '0644'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- current_user_roles_asset_value: "{{ user_roles_lookvar }}"
- when: user_roles_lookvar | length > 0
+ __dest: "{{ output_path }}/user_roles.yaml"
+ block:
+ - name: "Stat if the output file exists"
+ ansible.builtin.stat:
+ path: "{{ __dest }}"
+ register: user_roles_file
+
+ - name: "Add current user roles to the user roles flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_user_roles.j2') }}"
+ vars:
+ current_user_roles_asset_value: "{{ user_roles_lookvar }}"
+ first_user_role: "{{ not user_roles_file.stat.exists }}"
+ when: user_roles_lookvar | length > 0
+
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for user roles: {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ output_path }}/user_roles"
+ state: directory
+ mode: '0755'
+
+ - name: "Add current roles to the output yaml file"
+ ansible.builtin.template:
+ src: "templates/current_user_roles.j2"
+ dest: "{{ output_path }}/user_roles/current_roles_{{ username | regex_replace('/', '_') }}.yaml"
+ mode: '0644'
+ vars:
+ current_user_roles_asset_value: "{{ user_roles_lookvar }}"
+ when: user_roles_lookvar | length > 0
...
diff --git a/roles/filetree_create/tasks/users.yml b/roles/filetree_create/tasks/users.yml
index e99566e2f..aee2d8f17 100644
--- a/roles/filetree_create/tasks/users.yml
+++ b/roles/filetree_create/tasks/users.yml
@@ -9,7 +9,7 @@
- name: "Add the users the Organizations information" # noqa jinja[spacing]
ansible.builtin.set_fact:
- current_users: "{{ (current_users | default([])) + [user_lookvar_item | combine({'organizations': user_lookvar_item_organizations})] }}"
+ current_users: "{{ (current_users | default([])) + [user_lookvar_item | combine({'organizations': user_lookvar_item_organizations if (user_lookvar_item_organizations | length > 1) else ['ORGANIZATIONLESS']})] }}"
vars:
user_lookvar_item_organizations: "{{ query(controller_api_plugin, user_lookvar_item.related.organizations,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
@@ -22,35 +22,77 @@
label: "User {{ user_lookvar_item.username }}"
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the output directory for users in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ current_user_dir | regex_replace('/', '_') }}/users"
- loop: "{{ current_users | selectattr('organizations', 'defined') | map(attribute='organizations') | flatten | unique }}"
- loop_control:
- loop_var: current_user_dir
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/users.yaml"
+ block:
+ - name: "Add current users to the users flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_users.j2') }}"
+ vars:
+ current_users_asset_value: "{{ current_user_dir.0 }}"
+ last_user: "{{ current_user_index == ((users_lookvar | length) - 1) }}"
+ when: organization_filter is not defined or (current_user_dir.1 is match(organization_filter))
+ loop: "{{ current_users | default([]) | subelements('organizations', skip_missing=true) }}"
+ loop_control:
+ index_var: current_user_index
+ loop_var: current_user_dir
+ label: "{{ __dest }}"
-- name: "Add current users to the /.yaml output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_users.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- current_users_asset_value: "{{ current_user_dir.0 }}"
- __dest: "{{ output_path }}/{{ current_user_dir.1 | regex_replace('/', '_') }}/users/{{ current_user_dir.0.username | regex_replace('/', '_') }}.yaml"
- loop: "{{ current_users | subelements('organizations') }}"
- loop_control:
- loop_var: current_user_dir
- label: "{{ __dest }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the output directory for users in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ current_user_dir | regex_replace('/', '_') }}/users"
+ when: organization_filter is not defined or (current_user_dir is match(organization_filter))
+ loop: "{{ current_users | selectattr('organizations', 'defined') | map(attribute='organizations') | flatten | unique }}"
+ loop_control:
+ loop_var: current_user_dir
+ label: "{{ __path }}"
+
+ - name: "Add current users to the /.yaml output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_users.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ current_users_asset_value: "{{ current_user_dir.0 }}"
+ __dest: "{{ output_path }}/{{ current_user_dir.1 | regex_replace('/', '_') }}/users/{{ current_user_dir.0.username | regex_replace('/', '_') }}.yaml"
+ when: organization_filter is not defined or (current_user_dir.1 is match(organization_filter))
+ loop: "{{ current_users | default([]) | subelements('organizations', skip_missing=true) }}"
+ loop_control:
+ loop_var: current_user_dir
+ label: "{{ __dest }}"
- name: "Set the user's roles"
ansible.builtin.include_tasks: "user_roles.yml"
vars:
- username: "{{ item.username }}"
- loop: "{{ users_lookvar }}"
- when: not item.is_superuser
+ username: "{{ current_user.0.username }}"
+ last_user_role: "{{ current_user_index_for_roles == ((current_users | default([]) | subelements('organizations', skip_missing=true) | length) - 1) }}"
+ when:
+ - not current_user.0.is_superuser
+ - organization_filter is not defined or (current_user.1 is match(organization_filter))
+ loop: "{{ current_users | default([]) | subelements('organizations', skip_missing=true) }}"
+ loop_control:
+ index_var: current_user_index_for_roles
+ loop_var: current_user
...
diff --git a/roles/filetree_create/tasks/workflow_job_templates.yml b/roles/filetree_create/tasks/workflow_job_templates.yml
index 0f4655130..32e3c56ef 100644
--- a/roles/filetree_create/tasks/workflow_job_templates.yml
+++ b/roles/filetree_create/tasks/workflow_job_templates.yml
@@ -2,54 +2,108 @@
- name: "Get current Workflow Job Templates from the API"
ansible.builtin.set_fact:
workflow_job_templates_lookvar: "{{ query(controller_api_plugin, 'api/v2/workflow_job_templates/',
- query_params={'order_by': 'organization,id'},
+ query_params=(query_params | combine({'organization': organization_id})) if organization_id is defined else query_params,
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
+ vars:
+ query_params:
+ order_by: 'organization,id'
no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Create the /workflow_job_templates output directory for workflow job templates in {{ output_path }}"
- ansible.builtin.file:
- path: "{{ __path }}"
- state: directory
- mode: '0755'
+- name: "Block for to generate flatten output"
+ when:
+ - flatten_output is defined
+ - flatten_output | bool
vars:
- __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/workflow_job_templates/"
- loop: "{{ (workflow_job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
- + (['ORGANIZATIONLESS'] if ((workflow_job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
- }}"
- loop_control:
- loop_var: needed_path
- label: "{{ __path }}"
+ __dest: "{{ output_path }}/workflow_job_templates.yaml"
+ block:
+ - name: "Add current workflow_job_templates to the workflow_job_templates flat file"
+ ansible.builtin.blockinfile:
+ create: true
+ mode: "0644"
+ insertafter: EOF
+ path: "{{ __dest }}"
+ marker: ""
+ block: "{{ lookup('template', 'templates/current_workflow_job_templates.j2') }}"
+ vars:
+ workflow_job_template_organization: "{{ current_workflow_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ workflow_job_template_id: "{{ current_workflow_job_templates_asset_value.id }}"
+ workflow_job_template_name: "{{ current_workflow_job_templates_asset_value.name | regex_replace('/', '_') }}"
+ query_labels: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_error: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_approvals: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_approvals,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ last_workflow_job_template: "{{ current_workflow_job_template_index == ((workflow_job_templates_lookvar | length) - 1) }}"
+ loop: "{{ workflow_job_templates_lookvar }}"
+ loop_control:
+ index_var: current_workflow_job_template_index
+ loop_var: current_workflow_job_templates_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
-- name: "Add current workflow job templates to the /workflow_job_templates output file in {{ output_path }}"
- ansible.builtin.template:
- src: "templates/current_workflow_job_templates.j2"
- dest: "{{ __dest }}"
- mode: '0644'
- vars:
- workflow_job_template_organization: "{{ current_workflow_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
- workflow_job_template_id: "{{ current_workflow_job_templates_asset_value.id }}"
- workflow_job_template_name: "{{ current_workflow_job_templates_asset_value.name | regex_replace('/', '_') }}"
- __dest: "{{ output_path }}/{{ workflow_job_template_organization | regex_replace('/', '_') }}/workflow_job_templates/{{ workflow_job_template_id }}_{{ workflow_job_template_name | regex_replace('/', '_') }}.yaml"
- query_labels: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.labels,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_error: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_error,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_started: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_started,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_success: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_success,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- query_notification_approvals: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_approvals,
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects) }}"
- loop: "{{ workflow_job_templates_lookvar }}"
- loop_control:
- loop_var: current_workflow_job_templates_asset_value
- label: "{{ __dest }}"
- no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
+ - name: "Remove all the blank lines introduced by the last task"
+ ansible.builtin.lineinfile:
+ path: "{{ __dest }}"
+ line: ''
+ state: absent
+
+- name: "Block for to generate the filetre_create normal output"
+ when: flatten_output is not defined or not (flatten_output | bool)
+ block:
+ - name: "Create the /workflow_job_templates output directory for workflow job templates in {{ output_path }}"
+ ansible.builtin.file:
+ path: "{{ __path }}"
+ state: directory
+ mode: '0755'
+ vars:
+ __path: "{{ output_path }}/{{ needed_path | regex_replace('/', '_') }}/workflow_job_templates/"
+ loop: "{{ (workflow_job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'defined') | map(attribute='organization') | map(attribute='name') | list | flatten | unique)
+ + (['ORGANIZATIONLESS'] if ((workflow_job_templates_lookvar | map(attribute='summary_fields') | selectattr('organization', 'undefined') | list | flatten) | length > 0) else [])
+ }}"
+ loop_control:
+ loop_var: needed_path
+ label: "{{ __path }}"
+
+ - name: "Add current workflow job templates to the /workflow_job_templates output file in {{ output_path }}"
+ ansible.builtin.template:
+ src: "templates/current_workflow_job_templates.j2"
+ dest: "{{ __dest }}"
+ mode: '0644'
+ vars:
+ workflow_job_template_organization: "{{ current_workflow_job_templates_asset_value.summary_fields.organization.name | default('ORGANIZATIONLESS') }}"
+ workflow_job_template_id: "{{ current_workflow_job_templates_asset_value.id }}"
+ workflow_job_template_name: "{{ current_workflow_job_templates_asset_value.name | regex_replace('/', '_') }}"
+ __dest: "{{ output_path }}/{{ workflow_job_template_organization | regex_replace('/', '_') }}/workflow_job_templates/{{ workflow_job_template_id }}_{{ workflow_job_template_name | regex_replace('/', '_') }}.yaml"
+ query_labels: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.labels,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_error: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_error,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_started: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_started,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_success: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_success,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ query_notification_approvals: "{{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.notification_templates_approvals,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects) }}"
+ loop: "{{ workflow_job_templates_lookvar }}"
+ loop_control:
+ loop_var: current_workflow_job_templates_asset_value
+ label: "{{ __dest }}"
+ no_log: "{{ controller_configuration_filetree_create_secure_logging }}"
...
diff --git a/roles/filetree_create/templates/current_applications.j2 b/roles/filetree_create/templates/current_applications.j2
index c27915117..246ba3ed4 100644
--- a/roles/filetree_create/templates/current_applications.j2
+++ b/roles/filetree_create/templates/current_applications.j2
@@ -1,5 +1,7 @@
+{% if (current_application_index | default(0)) == 0 %}
---
controller_applications:
+{% endif %}
- name: "{{ current_applications_asset_value.name }}"
description: "{{ current_applications_asset_value.description }}"
organization: "{{ current_applications_asset_value.summary_fields.organization.name | default('ToDo: The application \'' + current_applications_asset_value.name + '\' must have an organization') }}"
@@ -8,4 +10,6 @@ controller_applications:
skip_authorization: "{{ current_applications_asset_value.skip_authorization }}"
client_id: "{{ current_applications_asset_value.client_id }}"
client_type: "{{ current_applications_asset_value.client_type }}"
+{% if last_application | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_credentials.j2 b/roles/filetree_create/templates/current_credentials.j2
index e9aeed9d9..d208a5d4e 100644
--- a/roles/filetree_create/templates/current_credentials.j2
+++ b/roles/filetree_create/templates/current_credentials.j2
@@ -1,11 +1,19 @@
+{% if (current_credential_index | default(0)) == 0 %}
---
controller_credentials:
+{% endif %}
- name: "{{ current_credentials_asset_value.name }}"
description: "{{ current_credentials_asset_value.description }}"
credential_type: "{{ current_credentials_asset_value.summary_fields.credential_type.name }}"
{% if current_credentials_asset_value.organization is defined and current_credentials_asset_value.organization is not none %}
organization: "{{ current_credentials_asset_value.summary_fields.organization.name }}"
+{% else %}
+ organization: "ORGANIZATIONLESS"
{% endif %}
+{% if current_credentials_asset_value.inputs is defined and current_credentials_asset_value.inputs is not match('{}') %}
inputs:
{{ current_credentials_asset_value.inputs | to_nice_yaml(indent=2) | indent(width=6, first=True) | replace("$encrypted$", "\'\'") }}
+{% endif %}
+{% if last_credential | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_execution_environments.j2 b/roles/filetree_create/templates/current_execution_environments.j2
index fbd6bcb4b..3c998f03c 100644
--- a/roles/filetree_create/templates/current_execution_environments.j2
+++ b/roles/filetree_create/templates/current_execution_environments.j2
@@ -1,12 +1,17 @@
---
controller_execution_environments:
{% for ee in current_execution_environments_asset_value %}
+{% if organization_filter is not defined or (ee.summary_fields.organization is defined and ee.summary_fields.organization.name is match(organization_filter)) %}
- name: "{{ ee.name }}"
description: "{{ ee.description }}"
+{% if ee.summary_fields.organization.name is defined %}
+ organization: "{{ ee.summary_fields.organization.name }}"
+{% endif %}
image: "{{ ee.image }}"
pull: "{{ ee.pull }}"
{% if ee.summary_fields.credential is defined %}
credential: "{{ ee.summary_fields.credential.name }}"
{% endif %}
+{% endif %}
{% endfor %}
...
diff --git a/roles/filetree_create/templates/current_groups.j2 b/roles/filetree_create/templates/current_groups.j2
index de8858bb5..a043e645e 100644
--- a/roles/filetree_create/templates/current_groups.j2
+++ b/roles/filetree_create/templates/current_groups.j2
@@ -1,5 +1,7 @@
+{% if ((first_inventory | default(true) | bool) and ((current_inventory_index | default(0)) == 0)) %}
---
controller_groups:
+{% endif %}
{% for group in current_groups_asset_value %}
- name: "{{ group.name }}"
description: "{{ group.description }}"
@@ -15,4 +17,6 @@ controller_groups:
) | selectattr("name", "defined") | map(attribute="name") | to_nice_yaml(indent=2) | indent(width=6, first=True)
}}
{%- endfor -%}
+{% if last_inventory | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_hosts.j2 b/roles/filetree_create/templates/current_hosts.j2
index 3a3d4abef..7ef807915 100644
--- a/roles/filetree_create/templates/current_hosts.j2
+++ b/roles/filetree_create/templates/current_hosts.j2
@@ -1,5 +1,7 @@
+{% if ((first_inventory | default(true) | bool) and ((current_inventory_index | default(0)) == 0)) %}
---
controller_hosts:
+{% endif %}
{% for host in current_hosts_asset_value if not host.has_inventory_sources %}
- name: "{{ host.name }}"
description: "{{ host.description }}"
@@ -9,4 +11,6 @@ controller_hosts:
{{ host.variables | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
{%- endif %}
{% endfor %}
+{% if last_inventory | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_inventories.j2 b/roles/filetree_create/templates/current_inventories.j2
index fadc76324..91c243bc3 100644
--- a/roles/filetree_create/templates/current_inventories.j2
+++ b/roles/filetree_create/templates/current_inventories.j2
@@ -1,16 +1,36 @@
+{% if (first_inventory | default(true) | bool) and (current_inventory_index | default(0) == 0) %}
---
controller_inventories:
+{% endif %}
- name: "{{ current_inventories_asset_value.name }}"
description: "{{ current_inventories_asset_value.description }}"
organization: "{{ inventory_organization }}"
-{% if current_inventories_asset_value.host_filter %}
+{% if current_inventories_asset_value.host_filter is defined %}
host_filter: "{{ current_inventories_asset_value.host_filter }}"
{% endif %}
{% if current_inventories_asset_value.kind %}
kind: "{{ current_inventories_asset_value.kind }}"
{% endif %}
-{% if current_inventories_asset_value.variables and current_inventories_asset_value.variables != '---' and current_inventories_asset_value.variables != '' %}
+{% if current_inventories_asset_value.prevent_instance_group_fallback is defined %}
+ prevent_instance_group_fallback: {{ current_inventories_asset_value.prevent_instance_group_fallback }}
+{% endif %}
+{% if current_inventories_asset_value.source_vars is defined %}
+ source_vars:
+ {{ current_inventories_asset_value.source_vars | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
+{% endif %}
+{% if current_inventories_asset_value.update_cache_timeout is defined %}
+ update_cache_timeout: {{ current_inventories_asset_value.update_cache_timeout }}
+{% endif %}
+{% if current_inventories_asset_value.limit is defined %}
+ limit: "{{ current_inventories_asset_value.limit }}"
+{% endif %}
+{% if current_inventories_asset_value.verbosity is defined %}
+ verbosity: {{ current_inventories_asset_value.verbosity }}
+{% endif %}
+{% if current_inventories_asset_value.variables is defined and current_inventories_asset_value.variables != '---' and current_inventories_asset_value.variables != '' %}
variables:
{{ current_inventories_asset_value.variables | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
{%- endif %}
+{% if last_inventory | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_inventory_sources.j2 b/roles/filetree_create/templates/current_inventory_sources.j2
index f6d8f258b..ab1c93936 100644
--- a/roles/filetree_create/templates/current_inventory_sources.j2
+++ b/roles/filetree_create/templates/current_inventory_sources.j2
@@ -1,9 +1,13 @@
+{% if (current_inventory_index | default(0)) == 0 %}
---
controller_inventory_sources:
+{% endif %}
{% for inventory_source in current_inventory_sources_asset_value %}
- name: "{{ inventory_source.name }}"
description: "{{ inventory_source.description }}"
+{% if inventory_source.summary_fields.organization %}
organization: "{{ inventory_source.summary_fields.organization.name }}"
+{% endif %}
source: "{{ inventory_source.source | default('ToDo: The source of the inventory_source was originally missing and must be specified',true) }}"
{% if inventory_source.source_project %}
source_project: "{{ inventory_source.summary_fields.source_project.name }}"
@@ -49,4 +53,6 @@ controller_inventory_sources:
{% endfor %}
{% endif %}
{% endfor %}
+{% if last_inventory | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_job_templates.j2 b/roles/filetree_create/templates/current_job_templates.j2
index 9e172c71f..c9c160cbc 100644
--- a/roles/filetree_create/templates/current_job_templates.j2
+++ b/roles/filetree_create/templates/current_job_templates.j2
@@ -1,5 +1,7 @@
+{% if (current_job_template_index | default(0)) == 0 %}
---
controller_templates:
+{% endif %}
- name: "{{ current_job_templates_asset_value.name }}"
description: "{{ current_job_templates_asset_value.description }}"
organization: "{{ current_job_templates_asset_value.summary_fields.organization.name | default('ToDo: The job template \'' + current_job_templates_asset_value.name + '\' must belong to an organization') }}"
@@ -8,29 +10,64 @@ controller_templates:
inventory: "{{ current_job_templates_asset_value.summary_fields.inventory.name }}"
{% endif %}
playbook: "{{ current_job_templates_asset_value.playbook }}"
+ scm_branch: "{{ current_job_templates_asset_value.scm_branch }}"
+ forks: {{ current_job_templates_asset_value.forks }}
+ limit: "{{ current_job_templates_asset_value.limit }}"
+ verbosity: {{ current_job_templates_asset_value.verbosity }}
job_type: "{{ current_job_templates_asset_value.job_type }}"
- fact_caching_enabled: "{{ current_job_templates_asset_value.use_fact_cache }}"
+ job_slice_count: {{ current_job_templates_asset_value.job_slice_count }}
+ use_fact_cache: {{ current_job_templates_asset_value.use_fact_cache | bool }}
{% if current_job_templates_asset_value.summary_fields.credentials %}
credentials:
{% for credential in current_job_templates_asset_value.summary_fields.credentials %}
- "{{ credential.name }}"
{% endfor %}
{% endif %}
- concurrent_jobs_enabled: "{{ current_job_templates_asset_value.allow_simultaneous }}"
- ask_scm_branch_on_launch: "{{ current_job_templates_asset_value.ask_scm_branch_on_launch }}"
- ask_tags_on_launch: "{{ current_job_templates_asset_value.ask_tags_on_launch }}"
- ask_verbosity_on_launch: "{{ current_job_templates_asset_value.ask_verbosity_on_launch }}"
- ask_variables_on_launch: "{{ current_job_templates_asset_value.ask_variables_on_launch }}"
-{% if current_job_templates_asset_value.extra_vars and current_job_templates_asset_value.extra_vars != '---' and current_job_templates_asset_value.extra_vars != '' %}
+ allow_simultaneous: {{ current_job_templates_asset_value.allow_simultaneous | bool }}
+ ask_scm_branch_on_launch: {{ current_job_templates_asset_value.ask_scm_branch_on_launch | bool }}
+ ask_diff_mode_on_launch: {{ current_job_templates_asset_value.ask_diff_mode_on_launch | bool }}
+ ask_tags_on_launch: {{ current_job_templates_asset_value.ask_tags_on_launch | bool }}
+ ask_skip_tags_on_launch: {{ current_job_templates_asset_value.ask_skip_tags_on_launch | bool }}
+ ask_job_type_on_launch: {{ current_job_templates_asset_value.ask_job_type_on_launch | bool }}
+ ask_verbosity_on_launch: {{ current_job_templates_asset_value.ask_verbosity_on_launch | bool }}
+ ask_variables_on_launch: {{ current_job_templates_asset_value.ask_variables_on_launch | bool }}
+ ask_inventory_on_launch: {{ current_job_templates_asset_value.ask_inventory_on_launch | bool }}
+ ask_limit_on_launch: {{ current_job_templates_asset_value.ask_limit_on_launch | bool }}
+ ask_credential_on_launch: {{ current_job_templates_asset_value.ask_credential_on_launch | bool }}
+{% if current_job_templates_asset_value.ask_execution_environment_on_launch is defined %}
+ ask_execution_environment_on_launch: {{ current_job_templates_asset_value.ask_execution_environment_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.ask_labels_on_launch is defined %}
+ ask_labels_on_launch: {{ current_job_templates_asset_value.ask_labels_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.ask_forks_on_launch is defined %}
+ ask_forks_on_launch: {{ current_job_templates_asset_value.ask_forks_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.ask_job_slice_count_on_launch is defined %}
+ ask_job_slice_count_on_launch: {{ current_job_templates_asset_value.ask_job_slice_count_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.ask_timeout_on_launch is defined %}
+ ask_timeout_on_launch: {{ current_job_templates_asset_value.ask_timeout_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.ask_instance_groups_on_launch is defined %}
+ ask_instance_groups_on_launch: {{ current_job_templates_asset_value.ask_instance_groups_on_launch | bool }}
+{% endif %}
+{% if current_job_templates_asset_value.extra_vars and current_job_templates_asset_value.extra_vars | length > 3 %}
extra_vars:
{{ current_job_templates_asset_value.extra_vars | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
{%- endif %}
-{% if is_aap %}
- execution_environment: "{{ current_job_templates_asset_value.summary_fields.execution_environment.name | default(omit) }}"
+ job_tags: "{{ current_job_templates_asset_value.job_tags }}"
+ force_handlers: {{ current_job_templates_asset_value.force_handlers | bool }}
+ skip_tags: "{{ current_job_templates_asset_value.skip_tags }}"
+ start_at_task: "{{ current_job_templates_asset_value.start_at_task }}"
+ timeout: {{ current_job_templates_asset_value.timeout | int }}
+{% if is_aap and current_job_templates_asset_value.summary_fields.execution_environment is defined %}
+ execution_environment: "{{ current_job_templates_asset_value.summary_fields.execution_environment.name }}"
{% endif %}
{% if not is_aap %}
custom_virtualenv: "{{ current_job_templates_asset_value.custom_virtualenv | default(omit) }}"
{% endif %}
+ host_config_key: "{{ current_job_templates_asset_value.host_config_key }}"
{% if query_labels | length > 0 %}
labels:
{% for label in query_labels %}
@@ -55,6 +92,24 @@ controller_templates:
- "{{ notification_success.name }}"
{% endfor %}
{% endif %}
- survey_enabled: {{ current_job_templates_asset_value.survey_enabled }}
- survey_spec: {{ query(controller_api_plugin, current_job_templates_asset_value.related.survey_spec, host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)[0] }}
+ survey_enabled: {{ current_job_templates_asset_value.survey_enabled | bool }}
+{% set survey_spec_contents = query(controller_api_plugin, current_job_templates_asset_value.related.survey_spec,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)[0] |
+ from_yaml | to_nice_yaml(indent=2,width=500) | regex_replace("\n\n[ ]*", "\\\\n") | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") | replace("^$", "")
+-%}
+{% if current_job_templates_asset_value.related.survey_spec is defined and survey_spec_contents | length > 3 %}
+ survey_spec:
+ {{ survey_spec_contents }}
+{% endif %}
+ become_enabled: {{ current_job_templates_asset_value.become_enabled | bool }}
+ diff_mode: {{ current_job_templates_asset_value.diff_mode | bool }}
+ webhook_service: "{{ current_job_templates_asset_value.webhook_service }}"
+{% if current_job_templates_asset_value.webhook_credential %}
+ webhook_credential: "{{ current_job_templates_asset_value.webhook_credential }}"
+{% endif %}
+{% if current_job_templates_asset_value.prevent_instance_group_fallback is defined %}
+ prevent_instance_group_fallback: {{ current_job_templates_asset_value.prevent_instance_group_fallback | bool }}
+{% endif %}
+{% if last_job_template | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_labels.j2 b/roles/filetree_create/templates/current_labels.j2
index 727cf90d8..fff70f1a6 100644
--- a/roles/filetree_create/templates/current_labels.j2
+++ b/roles/filetree_create/templates/current_labels.j2
@@ -1,5 +1,9 @@
+{% if (current_label_index | default(0)) == 0 %}
---
controller_labels:
+{% endif %}
- name: "{{ current_labels_asset_value.name }}"
organization: "{{ current_labels_asset_value.summary_fields.organization.name | default('ToDo: The label \'' + current_labels_asset_value.name + '\' must have an organization') }}"
+{% if last_label | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_notification_templates.j2 b/roles/filetree_create/templates/current_notification_templates.j2
index 66e21f1ee..ad60cb4cc 100644
--- a/roles/filetree_create/templates/current_notification_templates.j2
+++ b/roles/filetree_create/templates/current_notification_templates.j2
@@ -1,12 +1,26 @@
+{% if (current_notification_template_index | default(0)) == 0 %}
---
controller_notifications:
+{% endif %}
- name: "{{ current_notification_templates_asset_value.name }}"
organization: "{{ current_notification_templates_asset_value.summary_fields.organization.name }}"
notification_type: "{{ current_notification_templates_asset_value.notification_type }}"
notification_configuration:
-{{ current_notification_templates_asset_value.notification_configuration | to_nice_yaml(indent=2) | indent(width=6, first=True) }}
+{% for key,value in current_notification_templates_asset_value.notification_configuration.items() %}
+{% if value is mapping or (value | type_debug == 'list') %}
+ {{ key }}: {{ value }}
+{% elif (value | type_debug == 'int') %}
+ {{ key }}: {{ value | int }}
+{% elif (value | lower) is match('true') or (value | lower) is match('false') %}
+ {{ key }}: {{ value | bool }}
+{% else %}
+ {{ key }}: {{ '!unsafe ' if (value | regex_search('{{')) }}"{{ value | replace('\n','\\n') | replace('"', '\\"') }}"
+{% endif %}
+{% endfor %}
{% if current_notification_templates_asset_value.messages is defined and current_notification_templates_asset_value.messages %}
messages:
{{ current_notification_templates_asset_value.messages | to_nice_yaml(indent=2) | indent(width=6, first=True) | replace("'{{", "!unsafe \'{{") }}
{% endif %}
+{% if last_notification_template | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_organizations.j2 b/roles/filetree_create/templates/current_organizations.j2
index 3836f6ced..ea103a9cc 100644
--- a/roles/filetree_create/templates/current_organizations.j2
+++ b/roles/filetree_create/templates/current_organizations.j2
@@ -1,5 +1,7 @@
+{% if (current_organization_index | default(0)) == 0 %}
---
controller_organizations:
+{% endif %}
- name: "{{ current_organization.name }}"
description: "{{ current_organization.description }}"
{% if query_notification_error | length > 0 %}
@@ -26,4 +28,6 @@ controller_organizations:
- "{{ notification_approval.name }}"
{% endfor %}
{% endif %}
+{% if last_organization | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_projects.j2 b/roles/filetree_create/templates/current_projects.j2
index 5e9554006..9526f3356 100644
--- a/roles/filetree_create/templates/current_projects.j2
+++ b/roles/filetree_create/templates/current_projects.j2
@@ -1,5 +1,7 @@
+{% if (current_project_index | default(0)) == 0 %}
---
controller_projects:
+{% endif %}
- name: "{{ current_projects_asset_value.name }}"
description: "{{ current_projects_asset_value.description }}"
organization: "{{ current_projects_asset_value.summary_fields.organization.name | default('ToDo: The project \'' + current_projects_asset_value.name + '\' must have an organization') }}"
@@ -35,4 +37,6 @@ controller_projects:
- "{{ notification_success.name }}"
{% endfor %}
{% endif %}
+{% if last_project | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_schedules.j2 b/roles/filetree_create/templates/current_schedules.j2
new file mode 100644
index 000000000..8c7506815
--- /dev/null
+++ b/roles/filetree_create/templates/current_schedules.j2
@@ -0,0 +1,83 @@
+{% if (current_schedule_index | default(0)) == 0 %}
+---
+controller_schedules:
+{% endif %}
+ - name: "{{ current_schedules_asset_value.name }}"
+{% if current_schedules_asset_value.description is defined %}
+ description: "{{ current_schedules_asset_value.description }}"
+{% endif %}
+ enabled: {{ current_schedules_asset_value.enabled }}
+ unified_job_template: "{{ current_schedules_asset_value.summary_fields.unified_job_template.name }}"
+{% if current_schedules_asset_value.summary_fields.inventory is defined %}
+ inventory: "{{ current_schedules_asset_value.summary_fields.inventory.name }}"
+{% endif %}
+{% if query_instance_groups | length > 0 %}
+ instance_groups:
+{% for instance_group in query_instance_groups %}
+ - "{{ instance_group.name }}"
+{% endfor %}
+{% endif %}
+{% if current_schedules_asset_value.dtstart is defined %}
+ dtstart: "{{ current_schedules_asset_value.dtstart }}"
+{% endif %}
+{% if current_schedules_asset_value.dtend is defined %}
+ dtend: "{{ current_schedules_asset_value.dtend }}"
+{% endif %}
+{% if current_schedules_asset_value.timezone is defined %}
+ timezone: "{{ current_schedules_asset_value.timezone }}"
+{% endif %}
+{% if current_schedules_asset_value.rrule is defined %}
+ rrule: "{{ current_schedules_asset_value.rrule }}"
+{% endif %}
+{% if current_schedules_asset_value.summary_fields.execution_environment is defined %}
+ execution_environment: "{{ current_schedules_asset_value.summary_fields.execution_environment.name }}"
+{% endif %}
+{% if current_schedules_asset_value.extra_data is defined %}
+ extra_data:
+ {{ current_schedules_asset_value.extra_data | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
+{%- endif -%}
+{% if query_credentials | length > 0 %}
+ credentials:
+{% for credential in query_credentials %}
+ - "{{ credential.name }}"
+{% endfor %}
+{% endif %}
+{% if current_schedules_asset_value.scm_branch is defined %}
+ scm_branch: "{{ current_schedules_asset_value.scm_branch }}"
+{% endif %}
+{% if current_schedules_asset_value.forks is defined %}
+ forks: {{ current_schedules_asset_value.forks | int }}
+{% endif %}
+{% if current_schedules_asset_value.job_slice_count is defined %}
+ job_slice_count: {{ current_schedules_asset_value.job_slice_count | int }}
+{% endif %}
+{% if query_labels | length > 0 %}
+ labels:
+{% for label in query_labels %}
+ - "{{ label.name }}"
+{% endfor %}
+{% endif %}
+{% if current_schedules_asset_value.timeout is defined %}
+ timeout: {{ current_schedules_asset_value.timeout | int }}
+{% endif %}
+{% if current_schedules_asset_value.job_type is defined %}
+ job_type: "{{ current_schedules_asset_value.job_type }}"
+{% endif %}
+{% if current_schedules_asset_value.job_tags is defined %}
+ job_tags: "{{ current_schedules_asset_value.job_tags }}"
+{% endif %}
+{% if current_schedules_asset_value.skip_tags is defined %}
+ skip_tags: "{{ current_schedules_asset_value.skip_tags }}"
+{% endif %}
+{% if current_schedules_asset_value.limit is defined %}
+ limit: "{{ current_schedules_asset_value.limit }}"
+{% endif %}
+{% if current_schedules_asset_value.diff_mode is defined and current_schedules_asset_value.diff_mode | type_debug != "NoneType" %}
+ diff_mode: {{ current_schedules_asset_value.diff_mode | bool }}
+{% endif %}
+{% if current_schedules_asset_value.verbosity is defined %}
+ verbosity: {{ current_schedules_asset_value.verbosity | int }}
+{% endif %}
+{% if last_schedule | default(true) | bool %}
+...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_settings.j2 b/roles/filetree_create/templates/current_settings.j2
index 484e44838..3fd54f21f 100644
--- a/roles/filetree_create/templates/current_settings.j2
+++ b/roles/filetree_create/templates/current_settings.j2
@@ -1,5 +1,12 @@
---
controller_settings:
- settings:
-{{ changed_settings[0] | replace('\'AUTH_LDAP_GROUP_TYPE_PARAMS\': {}', '\'AUTH_LDAP_GROUP_TYPE_PARAMS\': {\'name_attr\': \'cn\', \'member_attr\': \'member\'}') | replace("'", '"') | replace(': True', ': true') | replace(': False', ': false') | replace(': None', ': null') | from_json | to_nice_yaml | indent(width=6, first=True) }}
+{% for key,value in changed_settings[0].items() %}
+{% if value is mapping or value | type_debug == "list" %}
+{{ key | indent(width=6, first=True) }}:
+{{ value | to_nice_yaml(indent=2) | indent(width=8, first=True) }}
+{%- else %}
+{{ key | indent(width=6, first=True) }}: "{{ value | replace('True', 'true') | replace('False', 'false') | replace('None', 'null') }}"
+{% endif %}
+{% endfor %}
...
diff --git a/roles/filetree_create/templates/current_team_roles.j2 b/roles/filetree_create/templates/current_team_roles.j2
index 61dda0ae9..d70d0a080 100644
--- a/roles/filetree_create/templates/current_team_roles.j2
+++ b/roles/filetree_create/templates/current_team_roles.j2
@@ -1,5 +1,7 @@
+{% if first_team_role | default(true) | bool %}
---
controller_roles:
+{% endif %}
{% for role in team_roles_lookvar %}
{% if role.summary_fields.resource_type is defined %}
- team: "{{ teamname }}"
@@ -23,4 +25,6 @@ controller_roles:
role: "{{ role.name | lower }}"
{% endif %}
{% endfor %}
+{% if last_team_role | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_teams.j2 b/roles/filetree_create/templates/current_teams.j2
index d8f471e24..259c47df8 100644
--- a/roles/filetree_create/templates/current_teams.j2
+++ b/roles/filetree_create/templates/current_teams.j2
@@ -1,6 +1,10 @@
+{% if (current_team_index | default(0)) == 0 %}
---
controller_teams:
+{% endif %}
- name: "{{ current_teams_asset_value.name }}"
description: "{{ current_teams_asset_value.description }}"
organization: "{{ current_teams_asset_value.summary_fields.organization.name }}"
+{% if last_team | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_user_roles.j2 b/roles/filetree_create/templates/current_user_roles.j2
index 2a037a5a7..2170e99d6 100644
--- a/roles/filetree_create/templates/current_user_roles.j2
+++ b/roles/filetree_create/templates/current_user_roles.j2
@@ -1,5 +1,7 @@
+{% if first_user_role | default(true) | bool %}
---
controller_roles:
+{% endif %}
{% for role in user_roles_lookvar %}
{% if role.summary_fields.resource_type is defined %}
- user: "{{ username }}"
@@ -23,4 +25,6 @@ controller_roles:
role: "{{ role.name | lower }}"
{% endif %}
{% endfor %}
+{% if last_user_role | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_users.j2 b/roles/filetree_create/templates/current_users.j2
index 89f64a148..59f766c2f 100644
--- a/roles/filetree_create/templates/current_users.j2
+++ b/roles/filetree_create/templates/current_users.j2
@@ -1,5 +1,7 @@
+{% if (current_user_index | default(0)) == 0 %}
---
controller_user_accounts:
+{% endif %}
- username: "{{ current_users_asset_value.username }}"
password: "INITIAL"
email: "{{ current_users_asset_value.email }}"
@@ -7,5 +9,7 @@ controller_user_accounts:
last_name: "{{ current_users_asset_value.last_name }}"
auditor: "{{ current_users_asset_value.is_system_auditor }}"
superuser: "{{ current_users_asset_value.is_superuser }}"
- update_secrets: False
+ update_secrets: false
+{% if last_user | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/templates/current_workflow_job_templates.j2 b/roles/filetree_create/templates/current_workflow_job_templates.j2
index 90fdb512f..6800a4215 100644
--- a/roles/filetree_create/templates/current_workflow_job_templates.j2
+++ b/roles/filetree_create/templates/current_workflow_job_templates.j2
@@ -1,5 +1,7 @@
+{% if (current_workflow_job_template_index | default(0)) == 0 %}
---
controller_workflows:
+{% endif %}
- name: "{{ current_workflow_job_templates_asset_value.name }}"
description: "{{ current_workflow_job_templates_asset_value.description }}"
organization: "{{ current_workflow_job_templates_asset_value.summary_fields.organization.name | default('ToDo: The WF \'' + current_workflow_job_templates_asset_value.name + '\' must belong to an organization') }}"
@@ -36,12 +38,11 @@ controller_workflows:
{% endfor %}
{% endif %}
{% endfor %}
- survey_enabled: "{{ current_workflow_job_templates_asset_value.survey_enabled }}"
ask_variables_on_launch: "{{ current_workflow_job_templates_asset_value.ask_variables_on_launch }}"
allow_simultaneous: "{{ current_workflow_job_templates_asset_value.allow_simultaneous }}"
scm_branch: "{{ current_workflow_job_templates_asset_value.scm_branch }}"
webhook_service: "{{ current_workflow_job_templates_asset_value.webhook_service }}"
-{% if current_workflow_job_templates_asset_value.extra_vars and current_workflow_job_templates_asset_value.extra_vars != '---' and current_workflow_job_templates_asset_value.extra_vars != '' %}
+{% if current_workflow_job_templates_asset_value.extra_vars and current_workflow_job_templates_asset_value.extra_vars | length > 3 %}
extra_vars:
{{ current_workflow_job_templates_asset_value.extra_vars | from_yaml | to_nice_yaml(indent=2) | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") }}
{%- endif %}
@@ -76,5 +77,14 @@ controller_workflows:
{% endfor %}
{% endif %}
survey_enabled: {{ current_workflow_job_templates_asset_value.survey_enabled }}
- survey_spec: {{ query(controller_api_plugin, current_workflow_job_templates_asset_value.related.survey_spec, host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)[0] }}
+{% set survey_spec_contents = query(controller_api_plugin, current_workflow_job_templates_asset_value.related.survey_spec,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)[0] |
+ from_yaml | to_nice_yaml(indent=2,width=500) | regex_replace("\n\n[ ]*", "\\\\n") | indent(width=6, first=False) | replace("'{{", "!unsafe \'{{") | replace("^$", "")
+-%}
+{% if current_workflow_job_templates_asset_value.related.survey_spec is defined and survey_spec_contents | length > 3 %}
+ survey_spec:
+ {{ survey_spec_contents }}
+{% endif %}
+{% if last_workflow_job_template | default(true) | bool %}
...
+{% endif %}
diff --git a/roles/filetree_create/tests/filetree_create.yml b/roles/filetree_create/tests/filetree_create.yml
index e54608a39..19e64aba7 100644
--- a/roles/filetree_create/tests/filetree_create.yml
+++ b/roles/filetree_create/tests/filetree_create.yml
@@ -47,3 +47,4 @@
status_code: 204
when: controller_oauthtoken_url is defined
...
+# ansible-playbook -i localhost, filetree_create.yml -e '{controller_configuration_inventories_enforce_defaults: false, controller_configuration_inventory_sources_enforce_defaults: false, controller_validate_certs: false, controller_hostname: localhost:8443, controller_username: , controller_password: , flatten_output: true}'
diff --git a/roles/filetree_create/vars/main.yml b/roles/filetree_create/vars/main.yml
index 844828d28..9c13f4ec9 100644
--- a/roles/filetree_create/vars/main.yml
+++ b/roles/filetree_create/vars/main.yml
@@ -21,4 +21,5 @@ valid_tags:
- instance_groups
- applications
- labels
+ - schedules
...
diff --git a/roles/filetree_read/tasks/applications.yml b/roles/filetree_read/tasks/applications.yml
index ac5638e0c..cebf3ead6 100644
--- a/roles/filetree_read/tasks/applications.yml
+++ b/roles/filetree_read/tasks/applications.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_applications_definitions_item
register: __contents_filetree_controller_applications
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_applications"
- name: "Populate Applications list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/credential_input_sources.yml b/roles/filetree_read/tasks/credential_input_sources.yml
index 27201d47a..a305c8332 100644
--- a/roles/filetree_read/tasks/credential_input_sources.yml
+++ b/roles/filetree_read/tasks/credential_input_sources.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_input_sources_definitions_item
register: __contents_filetree_controller_credential_input_sources
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_credential_input_sources"
- name: "Populate Credential Input Sources list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/credential_types.yml b/roles/filetree_read/tasks/credential_types.yml
index 90e51dde0..c72f69387 100644
--- a/roles/filetree_read/tasks/credential_types.yml
+++ b/roles/filetree_read/tasks/credential_types.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_credentials_definitions_item
register: __contents_filetree_controller_credential_types
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_credential_types"
- name: "Populate Credential_Types list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/credentials.yml b/roles/filetree_read/tasks/credentials.yml
index 3ff5661bb..10902d58b 100644
--- a/roles/filetree_read/tasks/credentials.yml
+++ b/roles/filetree_read/tasks/credentials.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_credentials_definitions_item
register: __contents_filetree_controller_credentials
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_credentials"
- name: "Populate Credentials list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/execution_environments.yml b/roles/filetree_read/tasks/execution_environments.yml
index 8dd80a77c..1060ffa78 100644
--- a/roles/filetree_read/tasks/execution_environments.yml
+++ b/roles/filetree_read/tasks/execution_environments.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_execution_environments_definitions_item
register: __contents_filetree_controller_execution_environments
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_execution_environments"
- name: "Populate Execution Environments list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/groups.yml b/roles/filetree_read/tasks/groups.yml
index 6f17d6e80..8e2c2afe8 100644
--- a/roles/filetree_read/tasks/groups.yml
+++ b/roles/filetree_read/tasks/groups.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_groups_definitions_item
register: __contents_filetree_controller_groups
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_groups"
- name: "Populate Groups list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/hosts.yml b/roles/filetree_read/tasks/hosts.yml
index ab7af5a2f..cb145b34c 100644
--- a/roles/filetree_read/tasks/hosts.yml
+++ b/roles/filetree_read/tasks/hosts.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_hosts_definitions_item
register: __contents_filetree_controller_hosts
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_hosts"
- name: "Populate Hosts list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/instance_groups.yml b/roles/filetree_read/tasks/instance_groups.yml
index f5a1e113b..03951ddd2 100644
--- a/roles/filetree_read/tasks/instance_groups.yml
+++ b/roles/filetree_read/tasks/instance_groups.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_instance_groups_definitions_item
register: __contents_filetree_controller_instance_groups
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_instance_groups"
- name: "Populate Instance Groups list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/inventories.yml b/roles/filetree_read/tasks/inventories.yml
index 6de650c3a..aa35a64d9 100644
--- a/roles/filetree_read/tasks/inventories.yml
+++ b/roles/filetree_read/tasks/inventories.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_inventories_definitions_item
register: __contents_filetree_controller_inventories
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_inventories"
- name: "Populate Inventories list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/inventory_sources.yml b/roles/filetree_read/tasks/inventory_sources.yml
index 1c5d457bd..f08001730 100644
--- a/roles/filetree_read/tasks/inventory_sources.yml
+++ b/roles/filetree_read/tasks/inventory_sources.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_inventory_sources_definitions_item
register: __contents_filetree_controller_inventory_sources
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_inventory_sources"
- name: "Populate Inventory Sources list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/job_templates.yml b/roles/filetree_read/tasks/job_templates.yml
index 287998c11..386a9a5dc 100644
--- a/roles/filetree_read/tasks/job_templates.yml
+++ b/roles/filetree_read/tasks/job_templates.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_job_templates_definitions_item
register: __contents_filetree_controller_templates
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_templates"
- name: "Populate Job Templates list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/labels.yml b/roles/filetree_read/tasks/labels.yml
index 16b8f51f9..721df02a4 100644
--- a/roles/filetree_read/tasks/labels.yml
+++ b/roles/filetree_read/tasks/labels.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_labels_definitions_item
register: __contents_filetree_controller_labels
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_labels"
- name: "Populate Labels list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/notifications.yml b/roles/filetree_read/tasks/notifications.yml
index f40c7db0f..058caaa35 100644
--- a/roles/filetree_read/tasks/notifications.yml
+++ b/roles/filetree_read/tasks/notifications.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_notifications_definitions_item
register: __contents_filetree_controller_notifications
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_notifications"
- name: "Populate Notifications list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/organizations.yml b/roles/filetree_read/tasks/organizations.yml
index 1fb04bd67..538e73cee 100644
--- a/roles/filetree_read/tasks/organizations.yml
+++ b/roles/filetree_read/tasks/organizations.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_organizations_definitions_item
register: __contents_filetree_controller_organizations
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_organizations"
- name: "Populate Organizations list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/projects.yml b/roles/filetree_read/tasks/projects.yml
index 83d9038e3..dd50fe91f 100644
--- a/roles/filetree_read/tasks/projects.yml
+++ b/roles/filetree_read/tasks/projects.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_projects_definitions_item
register: __contents_filetree_controller_projects
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_projects"
- name: "Populate Projects list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/roles.yml b/roles/filetree_read/tasks/roles.yml
index 3d9ec8c6c..ce7002fbe 100644
--- a/roles/filetree_read/tasks/roles.yml
+++ b/roles/filetree_read/tasks/roles.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_roles_definitions_item
register: __contents_filetree_controller_roles
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_roles"
- name: "Populate Roles list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/schedules.yml b/roles/filetree_read/tasks/schedules.yml
index a86d4df9b..e058cec6b 100644
--- a/roles/filetree_read/tasks/schedules.yml
+++ b/roles/filetree_read/tasks/schedules.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_schedules_definitions_item
register: __contents_filetree_controller_schedules
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_schedules"
- name: "Populate Schedules list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/settings.yml b/roles/filetree_read/tasks/settings.yml
index 0c850634d..3bdb60b28 100644
--- a/roles/filetree_read/tasks/settings.yml
+++ b/roles/filetree_read/tasks/settings.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_settings_definitions_item
register: __contents_filetree_controller_settings
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_settings"
- name: "Populate Settings list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/teams.yml b/roles/filetree_read/tasks/teams.yml
index 3b9a62b35..3c6a33f9d 100644
--- a/roles/filetree_read/tasks/teams.yml
+++ b/roles/filetree_read/tasks/teams.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_teams_definitions_item
register: __contents_filetree_controller_teams
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_teams"
- name: "Populate Teams list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/user_accounts.yml b/roles/filetree_read/tasks/user_accounts.yml
index 22b21711c..65ac0d400 100644
--- a/roles/filetree_read/tasks/user_accounts.yml
+++ b/roles/filetree_read/tasks/user_accounts.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_user_accounts_definitions_item
register: __contents_filetree_controller_user_accounts
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_user_accounts"
- name: "Populate User Accounts list"
ansible.builtin.set_fact:
diff --git a/roles/filetree_read/tasks/workflow_job_templates.yml b/roles/filetree_read/tasks/workflow_job_templates.yml
index baab23c38..00f586f91 100644
--- a/roles/filetree_read/tasks/workflow_job_templates.yml
+++ b/roles/filetree_read/tasks/workflow_job_templates.yml
@@ -13,6 +13,7 @@
loop_control:
loop_var: __read_credentials_definitions_item
register: __contents_filetree_controller_workflow_job_templates
+ failed_when: "'VARIABLE IS NOT DEFINED' in __contents_filetree_controller_workflow_job_templates"
- name: "Populate Workflow Job Templates list"
ansible.builtin.set_fact:
diff --git a/roles/global_vars/README.md b/roles/global_vars/README.md
new file mode 100644
index 000000000..2c9106280
--- /dev/null
+++ b/roles/global_vars/README.md
@@ -0,0 +1,45 @@
+# controller_configuration.global_vars
+
+## Description
+
+An ansible role to define global variables that will be available to all of the
+roles in the collection, if they are configured as follows:
+
+```console
+# tail -4 meta/main.yml
+
+dependencies:
+# List your role dependencies here, one per line. Be sure to remove the '[]' above,
+# if you add dependencies to this list.
+ - global_vars
+```
+
+## Provided Variables
+
+This is currently providing the following variables:
+
+| Variable Name | Default Value | Required | Description |
+|:---|:---:|:---:|:---|
+| `operation_translate` | [See the default value below](#operation_translate-default-value) | Yes | Provides translation from object states to human interpretation |
+
+### operation_translate Default value
+
+```yaml
+---
+operation_translate:
+ present:
+ verb: "Create/Update"
+ action: "creation"
+ absent:
+ verb: "Remove"
+ action: "deletion"
+...
+```
+
+## License
+
+[MIT](https://github.com/redhat-cop/controller_configuration#licensing)
+
+## Author
+
+[Ivan Aragonés](https://github.com/ivarmu)
diff --git a/roles/global_vars/defaults/main.yml b/roles/global_vars/defaults/main.yml
new file mode 100644
index 000000000..1abfda9ab
--- /dev/null
+++ b/roles/global_vars/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+# defaults file for global_vars
+operation_translate:
+ present:
+ verb: "Create/Update"
+ action: "creation"
+ absent:
+ verb: "Remove"
+ action: "deletion"
+...
diff --git a/roles/global_vars/meta/main.yml b/roles/global_vars/meta/main.yml
new file mode 100644
index 000000000..eb87d9e61
--- /dev/null
+++ b/roles/global_vars/meta/main.yml
@@ -0,0 +1,54 @@
+---
+galaxy_info:
+ author: "Ivan Aragonés"
+ description: "Global variables to be consumed by any other role in the collection"
+ company: "Red Hat"
+
+ # If the issue tracker for your role is not on github, uncomment the
+ # next line and provide a value
+ # issue_tracker_url: http://example.com/issue/tracker
+
+ # Choose a valid license ID from https://spdx.org - some suggested licenses:
+ # - BSD-3-Clause (default)
+ # - MIT
+ # - GPL-2.0-or-later
+ # - GPL-3.0-only
+ # - Apache-2.0
+ # - CC-BY-4.0
+ license: MIT
+
+ min_ansible_version: "2.1"
+
+ # If this a Container Enabled role, provide the minimum Ansible Container version.
+ # min_ansible_container_version:
+
+ #
+ # Provide a list of supported platforms, and for each platform a list of versions.
+ # If you don't wish to enumerate all versions for a particular platform, use 'all'.
+ # To view available platforms and versions (or releases), visit:
+ # https://galaxy.ansible.com/api/v1/platforms/
+ #
+ # platforms:
+ # - name: Fedora
+ # versions:
+ # - all
+ # - 25
+ # - name: SomePlatform
+ # versions:
+ # - all
+ # - 1.0
+ # - 7
+ # - 99.99
+
+ galaxy_tags: []
+ # List tags for your role here, one per line. A tag is a keyword that describes
+ # and categorizes the role. Users find roles by searching for tags. Be sure to
+ # remove the '[]' above, if you add tags to this list.
+ #
+ # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+ # Maximum 20 tags per role.
+
+dependencies: []
+# List your role dependencies here, one per line. Be sure to remove the '[]' above,
+# if you add dependencies to this list.
+...
diff --git a/roles/global_vars/vars/main.yml b/roles/global_vars/vars/main.yml
new file mode 100644
index 000000000..3e4311bb5
--- /dev/null
+++ b/roles/global_vars/vars/main.yml
@@ -0,0 +1,3 @@
+---
+# vars file for global_vars
+...
diff --git a/roles/groups/README.md b/roles/groups/README.md
index 307f44027..4153ceabc 100644
--- a/roles/groups/README.md
+++ b/roles/groups/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Groups on Ansible Controller.
+An Ansible Role to create/update/remove Groups on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_groups`|`see below`|yes|Data structure describing your group or groups Described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_groups_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_groups_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_groups_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_groups_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
### Formating Variables
diff --git a/roles/groups/defaults/main.yml b/roles/groups/defaults/main.yml
index 0bb75c6aa..2e26ec5fb 100644
--- a/roles/groups/defaults/main.yml
+++ b/roles/groups/defaults/main.yml
@@ -4,4 +4,6 @@ controller_groups: []
controller_configuration_group_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_group_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_group_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_groups_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/groups/meta/argument_specs.yml b/roles/groups/meta/argument_specs.yml
index 8b0b2a0a9..8ff25e66f 100644
--- a/roles/groups/meta/argument_specs.yml
+++ b/roles/groups/meta/argument_specs.yml
@@ -71,6 +71,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/groups/meta/main.yml b/roles/groups/meta/main.yml
index c5464bb13..33ea29973 100644
--- a/roles/groups/meta/main.yml
+++ b/roles/groups/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/groups/tasks/main.yml b/roles/groups/tasks/main.yml
index e93144cb3..7848f0959 100644
--- a/roles/groups/tasks/main.yml
+++ b/roles/groups/tasks/main.yml
@@ -1,38 +1,46 @@
---
# The group module is also an ansible.builtin module, but due to supporting both the awx.awx and automation.controller collections
# the FQCN cannot be used here.
-- name: Add controller group # noqa fqcn[action-core]
+- name: "Managing Controller Groups" # noqa fqcn[action-core]
group:
- name: "{{ controller_groups_item.name | mandatory }}"
- new_name: "{{ controller_groups_item.new_name | default(omit, true) }}"
- description: "{{ controller_groups_item.description | default(omit, true) }}"
- inventory: "{{ controller_groups_item.inventory | mandatory }}"
- variables: "{{ controller_groups_item.variables | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
- hosts: "{{ controller_groups_item.hosts | default(omit, true) }}"
- children: "{{ controller_groups_item.children | default(omit, true) }}"
- preserve_existing_hosts: "{{ controller_groups_item.preserve_existing_hosts | default(omit) }}"
- preserve_existing_children: "{{ controller_groups_item.preserve_existing_children | default(omit) }}"
- state: "{{ controller_groups_item.state | default(controller_state | default('present')) }}"
+ name: "{{ __controller_groups_item.name | mandatory }}"
+ new_name: "{{ __controller_groups_item.new_name | default(omit, true) }}"
+ description: "{{ __controller_groups_item.description | default(('' if controller_configuration_groups_enforce_defaults else omit), true) }}"
+ inventory: "{{ __controller_groups_item.inventory | mandatory }}"
+ variables: "{{ __controller_groups_item.variables | default(({} if controller_configuration_groups_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
+ hosts: "{{ __controller_groups_item.hosts | default(([] if controller_configuration_groups_enforce_defaults else omit), true) }}"
+ children: "{{ __controller_groups_item.children | default(([] if controller_configuration_groups_enforce_defaults else omit), true) }}"
+ preserve_existing_hosts: "{{ __controller_groups_item.preserve_existing_hosts | default((false if controller_configuration_groups_enforce_defaults else omit)) }}"
+ preserve_existing_children: "{{ __controller_groups_item.preserve_existing_children | default((false if controller_configuration_groups_enforce_defaults else omit)) }}"
+ state: "{{ __controller_groups_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_groups }}"
loop_control:
- loop_var: controller_groups_item
+ loop_var: __controller_groups_item
+ label: "{{ __operation.verb }} Controller Group {{ __controller_groups_item.name }}"
no_log: "{{ controller_configuration_group_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __group_job_async
changed_when: not __group_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_groups_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Create Controller Group | Wait for finish the Controller Group creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __group_job_async.failed is defined and __group_job_async.failed
+
+- name: "Managing Controller Groups | Wait for finish the Controller Groups management"
ansible.builtin.async_status:
jid: "{{ __group_job_async_results_item.ansible_job_id }}"
register: __group_job_async_result
@@ -42,8 +50,10 @@
loop: "{{ __group_job_async.results }}"
loop_control:
loop_var: __group_job_async_results_item
- when: __group_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Group {{ __group_job_async_results_item.__controller_groups_item.name }} | Wait for finish the Controller Group {{ __operation.action }}"
+ when: not ansible_check_mode and __group_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_group_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__group_job_async_results_item.__controller_groups_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/groups/tests/configs/group.yml b/roles/groups/tests/configs/group.yml
index 366fa179c..bfe65cd8b 100644
--- a/roles/groups/tests/configs/group.yml
+++ b/roles/groups/tests/configs/group.yml
@@ -1,7 +1,7 @@
---
controller_groups:
- - name: localhost
- inventory: My Inv
+ - name: localhost_group
+ inventory: localhost
variables:
my_var: true
...
diff --git a/roles/hosts/README.md b/roles/hosts/README.md
index a97a5684f..eade78f2f 100644
--- a/roles/hosts/README.md
+++ b/roles/hosts/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to add hosts on Ansible Controller.
+An Ansible Role to add/update/remove hosts on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_hosts`|`see below`|yes|Data structure describing your host entries described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_host_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_host_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_host_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_host_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
### Formating Variables
@@ -82,7 +98,7 @@ The role will strip the double space between the curly bracket in order to provi
|`new_name`|""|yes|str|To use when changing a hosts's name.|
|`description`|""|no|str|The description of the host.|
|`inventory`|""|yes|str|The inventory the host applies against.|
-|`enabled`|`True`|no|bool|If the host should be enabled.|
+|`enabled`||no|bool|If the host should be enabled.|
|`variables`|{}|no|str|The variables applicable to the host.|
|`state`|`present`|no|str|Desired state of the resource.|
diff --git a/roles/hosts/defaults/main.yml b/roles/hosts/defaults/main.yml
index 6decfba10..944825675 100644
--- a/roles/hosts/defaults/main.yml
+++ b/roles/hosts/defaults/main.yml
@@ -4,4 +4,6 @@ controller_hosts: []
controller_configuration_hosts_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_hosts_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_hosts_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_host_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/hosts/meta/argument_specs.yml b/roles/hosts/meta/argument_specs.yml
index 234dba67d..0cfa2ef60 100644
--- a/roles/hosts/meta/argument_specs.yml
+++ b/roles/hosts/meta/argument_specs.yml
@@ -56,6 +56,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/hosts/meta/main.yml b/roles/hosts/meta/main.yml
index 445ed9941..6a95ef857 100644
--- a/roles/hosts/meta/main.yml
+++ b/roles/hosts/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/hosts/tasks/main.yml b/roles/hosts/tasks/main.yml
index 99dcfcea8..146458c4f 100644
--- a/roles/hosts/tasks/main.yml
+++ b/roles/hosts/tasks/main.yml
@@ -1,33 +1,41 @@
---
-- name: Add Controller host
+- name: "Managing Controller Hosts"
host:
name: "{{ __controller_host_item.name | mandatory }}"
new_name: "{{ __controller_host_item.new_name | default(omit, true) }}"
- description: "{{ __controller_host_item.description | default(omit, true) }}"
+ description: "{{ __controller_host_item.description | default(('' if controller_configuration_host_enforce_defaults else omit), true) }}"
inventory: "{{ __controller_host_item.inventory | mandatory }}"
- enabled: "{{ __controller_host_item.enabled | default(omit) }}"
+ enabled: "{{ __controller_host_item.enabled | default((false if controller_configuration_host_enforce_defaults else omit), true) }}"
state: "{{ __controller_host_item.state | default(controller_state | default('present')) }}"
- variables: "{{ __controller_host_item.variables | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
+ variables: "{{ __controller_host_item.variables | default(({} if controller_configuration_host_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
# Role Standard Options
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_hosts }}"
loop_control:
loop_var: __controller_host_item
+ label: "{{ __operation.verb }} Controller host {{ __controller_host_item.name }}"
no_log: "{{ controller_configuration_hosts_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __host_job_async
changed_when: not __host_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_host_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Hosts | Wait for finish the Hosts creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __host_job_async.failed is defined and __host_job_async.failed
+
+- name: "Managing Controller Hosts | Wait for finish the Hosts management"
ansible.builtin.async_status:
jid: "{{ __host_job_async_results_item.ansible_job_id }}"
register: __host_job_async_result
@@ -37,8 +45,10 @@
loop: "{{ __host_job_async.results }}"
loop_control:
loop_var: __host_job_async_results_item
- when: __host_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Host {{ __host_job_async_results_item.__controller_host_item.name }} | Wait for finish the Hosts {{ __operation.action }}"
+ when: not ansible_check_mode and __host_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_hosts_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__host_job_async_results_item.__controller_host_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/hosts/tests/configs/host.yml b/roles/hosts/tests/configs/host.yml
index 34b7aab70..c6a59a032 100644
--- a/roles/hosts/tests/configs/host.yml
+++ b/roles/hosts/tests/configs/host.yml
@@ -1,7 +1,7 @@
---
-controller_host:
+controller_hosts:
- name: localhost
- inventory: My Inv
+ inventory: localhost
variables:
my_var: true
...
diff --git a/roles/hosts/tests/test.yml b/roles/hosts/tests/test.yml
index b7a00793d..e99a56994 100644
--- a/roles/hosts/tests/test.yml
+++ b/roles/hosts/tests/test.yml
@@ -19,5 +19,5 @@
extensions: ["yml"]
roles:
- - {role: ../.., when: controller_host is defined}
+ - {role: ../.., when: controller_hosts is defined}
...
diff --git a/roles/instance_groups/README.md b/roles/instance_groups/README.md
index 421f83184..bab234a25 100644
--- a/roles/instance_groups/README.md
+++ b/roles/instance_groups/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create instance groups on Ansible Controller.
+An Ansible Role to create/update/remove instance groups on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_instance_groups`|`see below`|yes|Data structure describing your instance groups Described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_instance_groups_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_instance_groups_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_instance_groups_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_instance_groups_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/instance_groups/defaults/main.yml b/roles/instance_groups/defaults/main.yml
index d7039ef73..1212c5cd8 100644
--- a/roles/instance_groups/defaults/main.yml
+++ b/roles/instance_groups/defaults/main.yml
@@ -3,4 +3,6 @@ controller_instance_groups: []
controller_configuration_instance_groups_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_instance_groups_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_instance_groups_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_instance_groups_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/instance_groups/meta/argument_specs.yml b/roles/instance_groups/meta/argument_specs.yml
index a1a52dfc0..17ddba3e8 100644
--- a/roles/instance_groups/meta/argument_specs.yml
+++ b/roles/instance_groups/meta/argument_specs.yml
@@ -80,6 +80,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/instance_groups/meta/main.yml b/roles/instance_groups/meta/main.yml
index ca726137e..b8a6c949b 100644
--- a/roles/instance_groups/meta/main.yml
+++ b/roles/instance_groups/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/instance_groups/tasks/main.yml b/roles/instance_groups/tasks/main.yml
index 38bf14270..f3d489d13 100644
--- a/roles/instance_groups/tasks/main.yml
+++ b/roles/instance_groups/tasks/main.yml
@@ -1,40 +1,47 @@
---
-# Add Controller Instance Group
-- name: Add Controller Instance Group
+- name: "Managing Controller Instance Groups"
instance_group:
name: "{{ __controller_instance_group_item.name | mandatory }}"
new_name: "{{ __controller_instance_group_item.new_name | default(omit, true) }}"
- credential: "{{ __controller_instance_group_item.credential | default(omit, true) }}"
- is_container_group: "{{ __controller_instance_group_item.is_container_group | default(omit, true) }}"
- policy_instance_percentage: "{{ __controller_instance_group_item.policy_instance_percentage | default(omit, true) }}"
- policy_instance_minimum: "{{ __controller_instance_group_item.policy_instance_minimum | default(omit, true) }}"
- policy_instance_list: "{{ __controller_instance_group_item.policy_instance_list | default(omit, true) }}"
- max_concurrent_jobs: "{{ __controller_instance_group_item.max_concurrent_jobs | default(omit, true) }}"
- max_forks: "{{ __controller_instance_group_item.max_forks | default(omit, true) }}"
- pod_spec_override: "{{ __controller_instance_group_item.pod_spec_override | default(omit, true) }}"
- instances: "{{ __controller_instance_group_item.instances | default(omit, true) }}"
+ credential: "{{ __controller_instance_group_item.credential | default(('' if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ is_container_group: "{{ __controller_instance_group_item.is_container_group | default((false if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ policy_instance_percentage: "{{ __controller_instance_group_item.policy_instance_percentage | default((0 if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ policy_instance_minimum: "{{ __controller_instance_group_item.policy_instance_minimum | default((0 if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ policy_instance_list: "{{ __controller_instance_group_item.policy_instance_list | default(([] if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ max_concurrent_jobs: "{{ __controller_instance_group_item.max_concurrent_jobs | default((0 if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ max_forks: "{{ __controller_instance_group_item.max_forks | default((0 if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ pod_spec_override: "{{ __controller_instance_group_item.pod_spec_override | default(('' if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
+ instances: "{{ __controller_instance_group_item.instances | default(([] if controller_configuration_instance_groups_enforce_defaults else omit), true) }}"
state: "{{ __controller_instance_group_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_instance_groups }}"
loop_control:
loop_var: __controller_instance_group_item
+ label: "{{ __operation.verb }} Controller Instance Group {{ __controller_instance_group_item.name }}"
no_log: "{{ controller_configuration_instance_groups_secure_logging }}"
when: controller_instance_groups is defined
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __instance_groups_job_async
changed_when: not __instance_groups_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_instance_group_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller instance groups | Wait for finish the instance groups creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __instance_groups_job_async.failed is defined and __instance_groups_job_async.failed
+
+- name: "Managing Controller instance groups | Wait for finish the instance groups management"
ansible.builtin.async_status:
jid: "{{ __instance_groups_job_async_results_item.ansible_job_id }}"
register: __instance_groups_job_async_result
@@ -44,8 +51,10 @@
loop: "{{ __instance_groups_job_async.results }}"
loop_control:
loop_var: __instance_groups_job_async_results_item
- when: __instance_groups_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller instance group {{ __instance_groups_job_async_results_item.__controller_instance_group_item.name }} | Wait for finish the instance groups {{ __operation.action }}"
+ when: not ansible_check_mode and __instance_groups_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_instance_groups_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__instance_groups_job_async_results_item.__controller_instance_group_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/instance_groups/tests/configs/instance_groups.yml b/roles/instance_groups/tests/configs/instance_groups.yml
index e9efbe31f..b66377066 100644
--- a/roles/instance_groups/tests/configs/instance_groups.yml
+++ b/roles/instance_groups/tests/configs/instance_groups.yml
@@ -1,4 +1,4 @@
---
controller_instance_groups:
- - name: test_instance_group
+ - name: test1
...
diff --git a/roles/instances/README.md b/roles/instances/README.md
index eca33da09..4901b16da 100644
--- a/roles/instances/README.md
+++ b/roles/instances/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_instances`|`see below`|yes|Data structure describing your instances Described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_instances_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_instances_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_instances_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_instances_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/instances/defaults/main.yml b/roles/instances/defaults/main.yml
index 53d5af675..af667d992 100644
--- a/roles/instances/defaults/main.yml
+++ b/roles/instances/defaults/main.yml
@@ -3,4 +3,6 @@ controller_instances: []
controller_configuration_instances_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_instances_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_instances_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_instances_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/instances/meta/argument_specs.yml b/roles/instances/meta/argument_specs.yml
index a68f53934..13c47503f 100644
--- a/roles/instances/meta/argument_specs.yml
+++ b/roles/instances/meta/argument_specs.yml
@@ -56,6 +56,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/instances/tasks/main.yml b/roles/instances/tasks/main.yml
index 3347ad0c2..c80428771 100644
--- a/roles/instances/tasks/main.yml
+++ b/roles/instances/tasks/main.yml
@@ -3,31 +3,38 @@
- name: Add Controller Instance
instance:
hostname: "{{ __controller_instance_item.hostname | mandatory }}"
- capacity_adjustment: "{{ __controller_instance_item.capacity_adjustment | default(omit, true) }}"
- enabled: "{{ __controller_instance_item.enabled | default(omit, true) }}"
- managed_by_policy: "{{ __controller_instance_item.managed_by_policy | default(omit, true) }}"
- node_type: "{{ __controller_instance_item.node_type | default('execution') }}"
- node_state: "{{ __controller_instance_item.node_state | default('installed') }}"
- listener_port: "{{ __controller_instance_item.listener_port | default(omit, true) }}"
+ capacity_adjustment: "{{ __controller_instance_item.capacity_adjustment | default((1.0 if controller_configuration_instances_enforce_defaults else omit), true) }}"
+ enabled: "{{ __controller_instance_item.enabled | default((true if controller_configuration_instances_enforce_defaults else omit), true) }}"
+ managed_by_policy: "{{ __controller_instance_item.managed_by_policy | default((true if controller_configuration_instances_enforce_defaults else omit), true) }}"
+ node_type: "{{ __controller_instance_item.node_type | default(omit, true) }}"
+ node_state: "{{ __controller_instance_item.node_state | default(omit, true) }}"
+ listener_port: "{{ __controller_instance_item.listener_port | default((27199 if controller_configuration_instances_enforce_defaults else omit), true) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_instances }}"
loop_control:
loop_var: __controller_instance_item
+ label: "{{ __controller_instance_item.hostname }}"
no_log: "{{ controller_configuration_instances_secure_logging }}"
when: controller_instances is defined
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __instance_job_async
changed_when: not __instance_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __instance_job_async.failed is defined and __instance_job_async.failed
- name: "Configure Controller instances | Wait for finish the instance creation"
ansible.builtin.async_status:
@@ -39,8 +46,8 @@
loop: "{{ __instance_job_async.results }}"
loop_control:
loop_var: __instance_job_async_results_item
- when: __instance_job_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __instance_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_instances_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/instances/tests/configs/instance_groups.yml b/roles/instances/tests/configs/instances.yml
similarity index 100%
rename from roles/instances/tests/configs/instance_groups.yml
rename to roles/instances/tests/configs/instances.yml
diff --git a/roles/inventories/README.md b/roles/inventories/README.md
index fcbed202c..fe3ea718e 100644
--- a/roles/inventories/README.md
+++ b/roles/inventories/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create inventories on Ansible Controller.
+An Ansible Role to create/update/remove inventories on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_inventories`|`see below`|yes|Data structure describing your inventories described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_inventories`|`see below`|yes|Data structure describing your inventories described below. Alias: inventory ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_inventories_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_inventories_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_inventories_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_inventories_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
### Formating Variables
@@ -79,10 +95,12 @@ The role will strip the double space between the curly bracket in order to provi
|Variable Name|Default Value|Required|type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`name`|""|yes|str|Name of this inventory.|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`copy_from`|""|no|str|Name or id to copy the inventory from. This will copy an existing inventory and change any parameters supplied.|
|`description`|""|no|str|Description of this inventory.|
|`organization`|""|yes|str|Organization this inventory belongs to.|
-|`instance_groups`|""|no|list|list of Instance Groups for this Inventory to run on.|
+|`instance_groups`|""|no|list|List of Instance Groups for this Inventory to run on.|
+|`input_inventories`|""|no|list|List of Inventories to use as input for Constructed Inventory.|
|`variables`|`{}`|no|dict|Variables for the inventory.|
|`kind`|""|no|str|The kind of inventory. Currently choices are '' and 'smart'|
|`host_filter`|""|no|str|The host filter field, useful only when 'kind=smart'|
diff --git a/roles/inventories/defaults/main.yml b/roles/inventories/defaults/main.yml
index c0dd7a1ea..4f8a3f46d 100644
--- a/roles/inventories/defaults/main.yml
+++ b/roles/inventories/defaults/main.yml
@@ -4,4 +4,6 @@ controller_inventories: []
controller_configuration_inventories_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_inventories_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_inventories_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_inventories_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/inventories/meta/argument_specs.yml b/roles/inventories/meta/argument_specs.yml
index 72446a2e9..35c58df6b 100644
--- a/roles/inventories/meta/argument_specs.yml
+++ b/roles/inventories/meta/argument_specs.yml
@@ -74,6 +74,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/inventories/meta/main.yml b/roles/inventories/meta/main.yml
index c02f4191b..41ca95146 100644
--- a/roles/inventories/meta/main.yml
+++ b/roles/inventories/meta/main.yml
@@ -26,4 +26,9 @@ galaxy_info:
collections:
- ansible.controller
- awx.awx
+
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/inventories/tasks/main.yml b/roles/inventories/tasks/main.yml
index 3bfca07ff..a9737351e 100644
--- a/roles/inventories/tasks/main.yml
+++ b/roles/inventories/tasks/main.yml
@@ -1,15 +1,17 @@
---
-- name: Create inventory
+- name: "Managing Inventories"
inventory:
name: "{{ __controller_inventory_item.name | mandatory }}"
+ new_name: "{{ __controller_inventory_item.new_name | default(omit, true) }}"
copy_from: "{{ __controller_inventory_item.copy_from | default(omit, true) }}"
- description: "{{ __controller_inventory_item.description | default(omit, true) }}"
+ description: "{{ __controller_inventory_item.description | default(('' if controller_configuration_inventories_enforce_defaults else omit), true) }}"
organization: "{{ __controller_inventory_item.organization.name | default(__controller_inventory_item.organization) | mandatory }}"
- instance_groups: "{{ __controller_inventory_item.instance_groups | default(omit, true) }}"
- variables: "{{ __controller_inventory_item.variables | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
- kind: "{{ __controller_inventory_item.kind | default(omit, true) }}"
- host_filter: "{{ __controller_inventory_item.host_filter | default(omit, true) }}"
- prevent_instance_group_fallback: "{{ __controller_inventory_item.prevent_instance_group_fallback | default(omit, true) }}"
+ instance_groups: "{{ __controller_inventory_item.instance_groups | default(([] if controller_configuration_inventories_enforce_defaults else omit), true) }}"
+ input_inventories: "{{ __controller_inventory_item.input_inventories | default(([] if controller_configuration_inventories_enforce_defaults else omit), true) }}"
+ variables: "{{ __controller_inventory_item.variables | default(({} if controller_configuration_inventories_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
+ kind: "{{ __controller_inventory_item.kind | default(('' if controller_configuration_inventories_enforce_defaults else omit), true) }}"
+ host_filter: "{{ __controller_inventory_item.host_filter | default(('' if controller_configuration_inventories_enforce_defaults else omit), true) }}"
+ prevent_instance_group_fallback: "{{ __controller_inventory_item.prevent_instance_group_fallback | default((false if controller_configuration_inventories_enforce_defaults else omit), true) }}"
state: "{{ __controller_inventory_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
@@ -17,20 +19,28 @@
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_inventories }}"
+ loop: "{{ inventory if inventory is defined else controller_inventories }}"
loop_control:
loop_var: __controller_inventory_item
+ label: "{{ __operation.verb }} inventory {{ __controller_inventory_item.name }}"
no_log: "{{ controller_configuration_inventories_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __inventories_job_async
changed_when: not __inventories_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_inventory_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Create Controller inventories | Wait for finish the inventories creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __inventories_job_async.failed is defined and __inventories_job_async.failed
+
+- name: "Managing Controller Inventories | Wait for finish the inventories management"
ansible.builtin.async_status:
jid: "{{ __inventories_job_async_result_item.ansible_job_id }}"
register: __inventories_job_async_result
@@ -40,8 +50,10 @@
loop: "{{ __inventories_job_async.results }}"
loop_control:
loop_var: __inventories_job_async_result_item
- when: __inventories_job_async_result_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller inventory {{ __inventories_job_async_result_item.__controller_inventory_item.name }} | Wait for finish the inventories {{ __operation.action }}"
+ when: not ansible_check_mode and __inventories_job_async_result_item.ansible_job_id is defined
no_log: "{{ controller_configuration_inventories_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__inventories_job_async_result_item.__controller_inventory_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/inventories/tests/configs/inventories.yml b/roles/inventories/tests/configs/inventories.yml
index 7e98e8710..bca330803 100644
--- a/roles/inventories/tests/configs/inventories.yml
+++ b/roles/inventories/tests/configs/inventories.yml
@@ -2,7 +2,9 @@
controller_inventories:
- name: test1
description: test inventory
+ organization: Default
- name: test2
+ organization: Default
kind: smart
host_filter: "name__icontains=test"
variables: '{"key1":"val1", "key2":"val2"}'
diff --git a/roles/inventory_source_update/README.md b/roles/inventory_source_update/README.md
index 5c0ed4b04..fb8bb735f 100644
--- a/roles/inventory_source_update/README.md
+++ b/roles/inventory_source_update/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,8 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_inventory_sources`|`see below`|yes|Data structure describing controller inventory sources to update Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_inventory_sources`|`see below`|yes|Data structure describing controller inventory sources to update Described below. Alias: inventory_sources ||
### Secure Logging Variables
@@ -51,6 +50,7 @@ This also speeds up the overall role.
|`controller_configuration_inventory_source_update_async_retries`|`controller_configuration_async_retries`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_inventory_source_update_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/inventory_source_update/defaults/main.yml b/roles/inventory_source_update/defaults/main.yml
index 136f6fc7c..84e12f551 100644
--- a/roles/inventory_source_update/defaults/main.yml
+++ b/roles/inventory_source_update/defaults/main.yml
@@ -2,4 +2,5 @@
controller_configuration_inventory_source_update_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_inventory_source_update_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_inventory_source_update_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
...
diff --git a/roles/inventory_source_update/meta/argument_specs.yml b/roles/inventory_source_update/meta/argument_specs.yml
index dd07fada4..0c81ed4d7 100644
--- a/roles/inventory_source_update/meta/argument_specs.yml
+++ b/roles/inventory_source_update/meta/argument_specs.yml
@@ -150,6 +150,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/inventory_source_update/tasks/main.yml b/roles/inventory_source_update/tasks/main.yml
index dee6e34b2..d9ccb5ef6 100644
--- a/roles/inventory_source_update/tasks/main.yml
+++ b/roles/inventory_source_update/tasks/main.yml
@@ -2,8 +2,8 @@
# Update Inventory sources
- name: Run Controller inventory source update
inventory_source_update:
- name: "{{ __inventory_source_update_item.name }}"
- inventory: "{{ __inventory_source_update_item.inventory }}"
+ name: "{{ __inventory_source_update_item.name | mandatory }}"
+ inventory: "{{ __inventory_source_update_item.inventory | mandatory }}"
organization: "{{ __inventory_source_update_item.organization | default(omit, true) }}"
wait: "{{ __inventory_source_update_item.wait | default(omit) }}"
interval: "{{ __inventory_source_update_item.interval | default(controller_configuration_inventory_source_update_async_delay) }}"
@@ -13,22 +13,29 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_inventory_sources }}"
+ loop: "{{ inventory_sources if inventory_sources is defined else controller_inventory_sources }}"
loop_control:
loop_var: "__inventory_source_update_item"
+ label: "{{ (__inventory_source_update_item.organization | default('')) }}/{{ __inventory_source_update_item.inventory }}/{{ __inventory_source_update_item.name }}"
no_log: "{{ controller_configuration_inventory_source_update_secure_logging }}"
when:
- controller_inventory_sources is defined
- __inventory_source_update_item.state | default('present') != "absent"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __inventory_source_update_async
changed_when: not __inventory_source_update_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __inventory_source_update_async.failed is defined and __inventory_source_update_async.failed
- name: "Controller inventory source update | Wait for finish of the inventory source update"
ansible.builtin.async_status:
@@ -40,8 +47,8 @@
loop: "{{ __inventory_source_update_async.results }}"
loop_control:
loop_var: __inventory_source_update_async_results_item
- when: __inventory_source_update_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __inventory_source_update_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_inventory_source_update_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/inventory_sources/README.md b/roles/inventory_sources/README.md
index 575790b66..f225a517a 100644
--- a/roles/inventory_sources/README.md
+++ b/roles/inventory_sources/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible role to create inventory sources on Ansible Controller.
+An Ansible Role to create/update/remove inventory sources on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_inventory_sources`|`see below`|yes|Data structure describing your inventory sources Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_inventory_sources`|`see below`|yes|Data structure describing your inventory sources Described below. Alias: inventory_sources ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_inventory_sources_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_inventory_sources_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_inventory_sources_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_inventory_sources_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
### Formating Variables
@@ -83,12 +99,13 @@ The role will strip the double space between the curly bracket in order to provi
|`description`|`False`|no|The description to use for the inventory source.|
|`inventory`|""|yes|Inventory the group should be made a member of.|
|`organization`|""|no|Organization the inventory belongs to.|
-|`source`|""|no|The source to use for this group.|
+|`source`|""|no|The source to use for this group. If set to `constructed` this role will be skipped as they are not meant to be edited.|
|`source_path`|""|no|For an SCM based inventory source, the source path points to the file within the repo to use as an inventory.|
|`source_vars`|""|no|The variables or environment fields to apply to this source type.|
|`enabled_var`|""|no|The variable to use to determine enabled state e.g., "status.power_state".|
|`enabled_value`|""|no|Value when the host is considered enabled, e.g., "powered_on".|
|`host_filter`|""|no|If specified, controller will only import hosts that match this regular expression.|
+|`limit`|""|no|Enter host, group or pattern match.|
|`credential`|""|no|Credential to use for the source.|
|`execution_environment`|""|no|Execution Environment to use for the source.|
|`overwrite`|""|no|Delete child groups and hosts not found in source.|
@@ -98,7 +115,8 @@ The role will strip the double space between the curly bracket in order to provi
|`verbosity`|""|no|The verbosity level to run this inventory source under.|
|`update_on_launch`|""|no|Refresh inventory data from its source each time a job is run.|
|`update_cache_timeout`|""|no|Time in seconds to consider an inventory sync to be current.|
-|`source_project`|""|no|Project to use as source with scm option|
+|`source_project`|""|no|Project to use as source with scm option.|
+|`scm_branch`|""|no|Project scm branch to use as source with scm option. Project must have branch override enabled.|
|`state`|`present`|no|Desired state of the resource.|
|`notification_templates_started`|""|no|The notifications on started to use for this inventory source in a list.|
|`notification_templates_success`|""|no|The notifications on success to use for this inventory source in a list.|
diff --git a/roles/inventory_sources/defaults/main.yml b/roles/inventory_sources/defaults/main.yml
index d1865c26b..d4b05271b 100644
--- a/roles/inventory_sources/defaults/main.yml
+++ b/roles/inventory_sources/defaults/main.yml
@@ -3,4 +3,6 @@ controller_inventory_sources: []
controller_configuration_inventory_sources_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_inventory_sources_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_inventory_sources_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_inventory_sources_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/inventory_sources/meta/argument_specs.yml b/roles/inventory_sources/meta/argument_specs.yml
index 8d584c5e7..022819924 100644
--- a/roles/inventory_sources/meta/argument_specs.yml
+++ b/roles/inventory_sources/meta/argument_specs.yml
@@ -150,6 +150,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/inventory_sources/meta/main.yml b/roles/inventory_sources/meta/main.yml
index 6dcc6b3de..78fdc7af8 100644
--- a/roles/inventory_sources/meta/main.yml
+++ b/roles/inventory_sources/meta/main.yml
@@ -26,4 +26,9 @@ galaxy_info:
collections:
- ansible.controller
- awx.awx
+
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/inventory_sources/tasks/main.yml b/roles/inventory_sources/tasks/main.yml
index 5542cd4cf..e778c6333 100644
--- a/roles/inventory_sources/tasks/main.yml
+++ b/roles/inventory_sources/tasks/main.yml
@@ -1,31 +1,33 @@
---
-- name: Add an inventory source
+- name: "Managing Inventory Sources"
inventory_source:
name: "{{ __controller_source_item.name | mandatory }}"
new_name: "{{ __controller_source_item.new_name | default(omit, true) }}"
- description: "{{ __controller_source_item.description | default(omit, true) }}"
+ description: "{{ __controller_source_item.description | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
inventory: "{{ __controller_source_item.inventory.name | default(__controller_source_item.inventory) | mandatory }}"
- organization: "{{ __controller_source_item.inventory.organization.name | default(__controller_source_item.organization | default(omit, true)) }}"
- source: "{{ __controller_source_item.source | default(omit, true) }}"
- source_path: "{{ __controller_source_item.source_path | default(omit, true) }}"
- source_vars: "{{ __controller_source_item.source_vars | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
- enabled_var: "{{ __controller_source_item.enabled_var | default(omit, true) }}"
- enabled_value: "{{ __controller_source_item.enabled_value | default(omit, true) }}"
- host_filter: "{{ __controller_source_item.host_filter | default(omit, true) }}"
+ organization: "{{ __controller_source_item.inventory.organization.name | default(__controller_source_item.organization | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true)) }}"
+ source: "{{ __controller_source_item.source | default(('scm' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ source_path: "{{ __controller_source_item.source_path | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ source_vars: "{{ __controller_source_item.source_vars | default(({} if controller_configuration_inventory_sources_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
+ enabled_var: "{{ __controller_source_item.enabled_var | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ enabled_value: "{{ __controller_source_item.enabled_value | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ host_filter: "{{ __controller_source_item.host_filter | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ limit: "{{ __controller_source_item.limit | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
credential: "{{ __controller_source_item.credential | default(omit, true) }}"
execution_environment: "{{ __controller_source_item.execution_environment | default(omit, true) }}"
- overwrite: "{{ __controller_source_item.overwrite | default(omit) }}"
- overwrite_vars: "{{ __controller_source_item.overwrite_vars | default(omit) }}"
- custom_virtualenv: "{{ __controller_source_item.custom_virtualenv | default(omit, true) }}"
- timeout: "{{ __controller_source_item.timeout | default(omit, true) }}"
- verbosity: "{{ __controller_source_item.verbosity | default(omit, true) }}"
- update_on_launch: "{{ __controller_source_item.update_on_launch | default(omit) }}"
- update_cache_timeout: "{{ __controller_source_item.update_cache_timeout | default(omit, true) }}"
- source_project: "{{ __controller_source_item.source_project.name | default(__controller_source_item.source_project | default(omit, true)) }}"
+ overwrite: "{{ __controller_source_item.overwrite | default((false if controller_configuration_inventory_sources_enforce_defaults else omit)) }}"
+ overwrite_vars: "{{ __controller_source_item.overwrite_vars | default((false if controller_configuration_inventory_sources_enforce_defaults else omit)) }}"
+ custom_virtualenv: "{{ __controller_source_item.custom_virtualenv | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ timeout: "{{ __controller_source_item.timeout | default((0 if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ verbosity: "{{ __controller_source_item.verbosity | default((1 if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ update_on_launch: "{{ __controller_source_item.update_on_launch | default((false if controller_configuration_inventory_sources_enforce_defaults else omit)) }}"
+ update_cache_timeout: "{{ __controller_source_item.update_cache_timeout | default((0 if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ source_project: "{{ __controller_source_item.source_project.name | default(__controller_source_item.source_project | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true)) }}"
+ scm_branch: "{{ __controller_source_item.scm_branch | default(('' if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
state: "{{ __controller_source_item.state | default(controller_state | default('present')) }}"
- notification_templates_started: "{{ __controller_source_item.notification_templates_started | default(__controller_source_item.related.notification_templates_started | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_success: "{{ __controller_source_item.notification_templates_success | default(__controller_source_item.related.notification_templates_success | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_error: "{{ __controller_source_item.notification_templates_error | default(__controller_source_item.related.notification_templates_error | default([]) | map(attribute='name') | list) | default(omit, true) }}"
+ notification_templates_started: "{{ (__controller_source_item.related.notification_templates_started | map(attribute='name') | list if __controller_source_item.related.notification_templates_started is defined) | default(__controller_source_item.notification_templates_started) | default(([] if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ notification_templates_success: "{{ (__controller_source_item.related.notification_templates_success | map(attribute='name') | list if __controller_source_item.related.notification_templates_success is defined) | default(__controller_source_item.notification_templates_success) | default(([] if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
+ notification_templates_error: "{{ (__controller_source_item.related.notification_templates_error | map(attribute='name') | list if __controller_source_item.related.notification_templates_error is defined) | default(__controller_source_item.notification_templates_error) | default(([] if controller_configuration_inventory_sources_enforce_defaults else omit), true) }}"
# Role Standard Options
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
@@ -33,19 +35,28 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_inventory_sources }}"
+ loop: "{{ inventory_sources if inventory_sources is defined else controller_inventory_sources }}"
loop_control:
loop_var: __controller_source_item
+ label: "{{ __operation.verb }} an Inventory Source {{ __controller_source_item.name }}"
no_log: "{{ controller_configuration_inventory_sources_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __inventory_source_job_async
changed_when: not __inventory_source_job_async.changed
+ when: __controller_source_item.source != "constructed"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_source_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Inventory Source | Wait for finish the Inventory Source creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __inventory_source_job_async.failed is defined and __inventory_source_job_async.failed
+
+- name: "Managing Inventory Sources | Wait for finish the Inventory Sources management"
ansible.builtin.async_status:
jid: "{{ __inventory_source_job_async_results_item.ansible_job_id }}"
register: __inventory_source_job_async_result
@@ -55,8 +66,10 @@
loop: "{{ __inventory_source_job_async.results }}"
loop_control:
loop_var: __inventory_source_job_async_results_item
- when: __inventory_source_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Inventory Source {{ __inventory_source_job_async_results_item }} | Wait for finish the Inventory Source {{ __operation.action }}"
+ when: not ansible_check_mode and __inventory_source_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_inventory_sources_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__inventory_source_job_async_results_item.__controller_source_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/job_launch/README.md b/roles/job_launch/README.md
index 1466bcc93..559646ea9 100644
--- a/roles/job_launch/README.md
+++ b/roles/job_launch/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,6 +22,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_launch_jobs`|`see below`|yes|Data structure describing the jobs to launch Described below.||
### Secure Logging Variables
diff --git a/roles/job_launch/tasks/main.yml b/roles/job_launch/tasks/main.yml
index 639ce39c1..d8e48afdf 100644
--- a/roles/job_launch/tasks/main.yml
+++ b/roles/job_launch/tasks/main.yml
@@ -29,12 +29,14 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_launch_jobs }}"
loop_control:
loop_var: "__job_launch_item"
+ label: "{{ (__job_launch_item.organization | default('')) }}/{{ __job_launch_item.name }}"
no_log: "{{ controller_configuration_job_launch_secure_logging }}"
register: launched_controller_jobs
when: controller_launch_jobs is defined
diff --git a/roles/job_templates/README.md b/roles/job_templates/README.md
index a472d3e1e..68e2dd9c0 100644
--- a/roles/job_templates/README.md
+++ b/roles/job_templates/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Job Templates on Ansible Controller.
+An Ansible Role to create/update/remove Job Templates on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_templates`|`see below`|yes|Data structure describing your job template or job templates Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_templates`|`see below`|yes|Data structure describing your job template or job templates Described below. Alias: job_templates ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_job_templates_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_job_templates_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_job_templates_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_job_templates_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/job_templates/defaults/main.yml b/roles/job_templates/defaults/main.yml
index a9462458c..5aaca4515 100644
--- a/roles/job_templates/defaults/main.yml
+++ b/roles/job_templates/defaults/main.yml
@@ -4,4 +4,6 @@ controller_templates: []
controller_configuration_job_templates_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_job_templates_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_job_templates_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_job_templates_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/job_templates/meta/argument_specs.yml b/roles/job_templates/meta/argument_specs.yml
index d28f7b6fe..69744c6f6 100644
--- a/roles/job_templates/meta/argument_specs.yml
+++ b/roles/job_templates/meta/argument_specs.yml
@@ -265,6 +265,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/job_templates/meta/main.yml b/roles/job_templates/meta/main.yml
index 4817f30f0..902407dd5 100644
--- a/roles/job_templates/meta/main.yml
+++ b/roles/job_templates/meta/main.yml
@@ -39,7 +39,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/job_templates/tasks/main.yml b/roles/job_templates/tasks/main.yml
index 3ac6f4292..315c3ab73 100644
--- a/roles/job_templates/tasks/main.yml
+++ b/roles/job_templates/tasks/main.yml
@@ -1,82 +1,89 @@
---
-# Create Controller Template
-- name: Add Controller Job Templates
+- name: "Managing Controller Job Templates"
job_template:
name: "{{ __controller_template_item.name | mandatory }}"
new_name: "{{ __controller_template_item.new_name | default(omit, true) }}"
copy_from: "{{ __controller_template_item.copy_from | default(omit, true) }}"
- description: "{{ __controller_template_item.description | default(omit, true) }}"
+ description: "{{ __controller_template_item.description | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
execution_environment: "{{ __controller_template_item.execution_environment.name | default(__controller_template_item.execution_environment | default(omit, true)) }}"
+ custom_virtualenv: "{{ __controller_template_item.custom_virtualenv | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
job_type: "{{ __controller_template_item.job_type | default('run') }}"
inventory: "{{ __controller_template_item.inventory.name | default(__controller_template_item.inventory | default(omit, true)) }}"
- organization: "{{ __controller_template_item.organization.name | default(__controller_template_item.organization | default(omit, true)) }}"
+ organization: "{{ __controller_template_item.organization.name | default(__controller_template_item.organization | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true)) }}"
project: "{{ __controller_template_item.project.name | default(__controller_template_item.project | default(omit, true)) }}"
playbook: "{{ __controller_template_item.playbook | default(omit, true) }}"
credentials: "{{ __controller_template_item.credentials | default(__controller_template_item.related.credentials | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- forks: "{{ __controller_template_item.forks | default(omit, true) }}"
- limit: "{{ __controller_template_item.limit | default(omit, true) }}"
- verbosity: "{{ __controller_template_item.verbosity | default(omit, true) }}"
- extra_vars: "{{ __controller_template_item.extra_vars | default(omit, true) }}"
- job_tags: "{{ __controller_template_item.job_tags | default(omit, true) }}"
- force_handlers: "{{ __controller_template_item.force_handlers | default(omit) }}"
- skip_tags: "{{ __controller_template_item.skip_tags | default(omit, true) }}"
- start_at_task: "{{ __controller_template_item.start_at_task | default(omit, true) }}"
- diff_mode: "{{ __controller_template_item.diff_mode | default(omit) }}"
- use_fact_cache: "{{ __controller_template_item.use_fact_cache | default(omit) }}"
- host_config_key: "{{ __controller_template_item.host_config_key | default(omit, true) }}"
- ask_scm_branch_on_launch: "{{ __controller_template_item.ask_scm_branch_on_launch | default(omit) }}"
- ask_diff_mode_on_launch: "{{ __controller_template_item.ask_diff_mode_on_launch | default(omit) }}"
- ask_variables_on_launch: "{{ __controller_template_item.ask_variables_on_launch | default(omit) }}"
- ask_limit_on_launch: "{{ __controller_template_item.ask_limit_on_launch | default(omit) }}"
- ask_tags_on_launch: "{{ __controller_template_item.ask_tags | default(__controller_template_item.ask_tags_on_launch | default(omit)) }}"
- ask_skip_tags_on_launch: "{{ __controller_template_item.ask_skip_tags | default(__controller_template_item.ask_skip_tags_on_launch | default(omit)) }}"
- ask_job_type_on_launch: "{{ __controller_template_item.ask_job_type_on_launch | default(omit) }}"
- ask_verbosity_on_launch: "{{ __controller_template_item.ask_verbosity_on_launch | default(omit) }}"
- ask_inventory_on_launch: "{{ __controller_template_item.ask_inventory_on_launch | default(omit) }}"
- ask_credential_on_launch: "{{ __controller_template_item.ask_credential_on_launch | default(omit) }}"
- ask_execution_environment_on_launch: "{{ __controller_template_item.ask_execution_environment_on_launch | default(omit) }}"
- ask_forks_on_launch: "{{ __controller_template_item.ask_forks_on_launch | default(omit) }}"
- ask_instance_groups_on_launch: "{{ __controller_template_item.ask_instance_groups_on_launch | default(omit) }}"
- ask_job_slice_count_on_launch: "{{ __controller_template_item.ask_job_slice_count_on_launch | default(omit) }}"
- ask_labels_on_launch: "{{ __controller_template_item.ask_labels_on_launch | default(omit) }}"
- ask_timeout_on_launch: "{{ __controller_template_item.ask_timeout_on_launch | default(omit) }}"
- prevent_instance_group_fallback: "{{ __controller_template_item.prevent_instance_group_fallback | default(omit) }}"
- survey_enabled: "{{ __controller_template_item.survey_enabled | default(omit) }}"
- survey_spec: "{{ __controller_template_item.related.survey_spec | default(__controller_template_item.survey_spec | default(__controller_template_item.survey | default(omit, true))) }}"
- become_enabled: "{{ __controller_template_item.become_enabled | default(omit) }}"
- allow_simultaneous: "{{ __controller_template_item.allow_simultaneous | default(omit) }}"
- timeout: "{{ __controller_template_item.timeout | default(omit, true) }}"
- custom_virtualenv: "{{ __controller_template_item.custom_virtualenv | default(omit, true) }}"
- instance_groups: "{{ __controller_template_item.instance_groups | default(omit, true) }}"
- job_slice_count: "{{ __controller_template_item.job_slice_count | default(omit, true) }}"
- webhook_service: "{{ __controller_template_item.webhook_service | default(omit, true) }}"
+ forks: "{{ __controller_template_item.forks | default((0 if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ limit: "{{ __controller_template_item.limit | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ verbosity: "{{ __controller_template_item.verbosity | default((0 if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ extra_vars: "{{ __controller_template_item.extra_vars | default(({} if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ job_tags: "{{ __controller_template_item.job_tags | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ force_handlers: "{{ __controller_template_item.force_handlers | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ skip_tags: "{{ __controller_template_item.skip_tags | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ start_at_task: "{{ __controller_template_item.start_at_task | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ diff_mode: "{{ __controller_template_item.diff_mode | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ use_fact_cache: "{{ __controller_template_item.use_fact_cache | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ host_config_key: "{{ __controller_template_item.host_config_key | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ ask_scm_branch_on_launch: "{{ __controller_template_item.ask_scm_branch_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_diff_mode_on_launch: "{{ __controller_template_item.ask_diff_mode_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_variables_on_launch: "{{ __controller_template_item.ask_variables_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_limit_on_launch: "{{ __controller_template_item.ask_limit_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_tags_on_launch: "{{ __controller_template_item.ask_tags | default(__controller_template_item.ask_tags_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit))) }}"
+ ask_skip_tags_on_launch: "{{ __controller_template_item.ask_skip_tags | default(__controller_template_item.ask_skip_tags_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit))) }}"
+ ask_job_type_on_launch: "{{ __controller_template_item.ask_job_type_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_verbosity_on_launch: "{{ __controller_template_item.ask_verbosity_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_inventory_on_launch: "{{ __controller_template_item.ask_inventory_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_credential_on_launch: "{{ __controller_template_item.ask_credential_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_execution_environment_on_launch: "{{ __controller_template_item.ask_execution_environment_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_forks_on_launch: "{{ __controller_template_item.ask_forks_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_instance_groups_on_launch: "{{ __controller_template_item.ask_instance_groups_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_job_slice_count_on_launch: "{{ __controller_template_item.ask_job_slice_count_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_labels_on_launch: "{{ __controller_template_item.ask_labels_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ ask_timeout_on_launch: "{{ __controller_template_item.ask_timeout_on_launch | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ prevent_instance_group_fallback: "{{ __controller_template_item.prevent_instance_group_fallback | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ survey_enabled: "{{ __controller_template_item.survey_enabled | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ survey_spec: "{{ __controller_template_item.related.survey_spec | default(__controller_template_item.survey_spec | default(__controller_template_item.survey | default(({} if controller_configuration_job_templates_enforce_defaults else omit), true))) }}"
+ become_enabled: "{{ __controller_template_item.become_enabled | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ allow_simultaneous: "{{ __controller_template_item.allow_simultaneous | default((false if controller_configuration_job_templates_enforce_defaults else omit)) }}"
+ timeout: "{{ __controller_template_item.timeout | default((0 if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ instance_groups: "{{ __controller_template_item.instance_groups | default(([] if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ job_slice_count: "{{ __controller_template_item.job_slice_count | default((1 if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ webhook_service: "{{ __controller_template_item.webhook_service | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
webhook_credential: "{{ __controller_template_item.webhook_credential | default(omit, true) }}"
- scm_branch: "{{ __controller_template_item.scm_branch | default(omit, true) }}"
- labels: "{{ __controller_template_item.labels | default(__controller_template_item.related.labels | default([]) | map(attribute='name') | list if __controller_template_item.related.labels is defined else omit) }}"
+ scm_branch: "{{ __controller_template_item.scm_branch | default(('' if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ labels: "{{ (__controller_template_item.related.labels | map(attribute='name') | list if __controller_template_item.related.labels is defined) | default(__controller_template_item.labels) | default(([] if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
state: "{{ __controller_template_item.state | default(controller_state | default('present')) }}"
- notification_templates_started: "{{ __controller_template_item.notification_templates_started | default(__controller_template_item.related.notification_templates_started | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_success: "{{ __controller_template_item.notification_templates_success | default(__controller_template_item.related.notification_templates_success | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_error: "{{ __controller_template_item.notification_templates_error | default(__controller_template_item.related.notification_templates_error | default([]) | map(attribute='name') | list) | default(omit, true) }}"
+ notification_templates_started: "{{ (__controller_template_item.related.notification_templates_started | map(attribute='name') | list if __controller_template_item.related.notification_templates_started is defined) | default(__controller_template_item.notification_templates_started) | default(([] if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ notification_templates_success: "{{ (__controller_template_item.related.notification_templates_success | map(attribute='name') | list if __controller_template_item.related.notification_templates_success is defined) | default(__controller_template_item.notification_templates_success) | default(([] if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
+ notification_templates_error: "{{ (__controller_template_item.related.notification_templates_error | map(attribute='name') | list if __controller_template_item.related.notification_templates_error is defined) | default(__controller_template_item.notification_templates_error) | default(([] if controller_configuration_job_templates_enforce_defaults else omit), true) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_templates }}"
+ loop: "{{ job_templates if job_templates is defined else controller_templates }}"
loop_control:
loop_var: __controller_template_item
+ label: "{{ __operation.verb }} Controller Job Template {{ __controller_template_item.name }}"
no_log: "{{ controller_configuration_job_templates_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __job_templates_job_async
changed_when: not __job_templates_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_template_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Job Templates | Wait for finish the job templates creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __job_templates_job_async.failed is defined and __job_templates_job_async.failed
+
+- name: "Managing Controller Job Templates | Wait for finish the Job Templates management"
ansible.builtin.async_status:
jid: "{{ __job_templates_job_async_result_item.ansible_job_id }}"
register: __job_templates_job_async_result
@@ -86,8 +93,10 @@
loop: "{{ __job_templates_job_async.results }}"
loop_control:
loop_var: __job_templates_job_async_result_item
- when: __job_templates_job_async_result_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Job Template {{ __job_templates_job_async_result_item.__controller_template_item.name }} | Wait for finish the job templates {{ __operation.action }}"
+ when: not ansible_check_mode and __job_templates_job_async_result_item.ansible_job_id is defined
no_log: "{{ controller_configuration_job_templates_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__job_templates_job_asycn_result_item.__controller_template_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/jobs_cancel/README.md b/roles/jobs_cancel/README.md
index 9c9c41e47..282839dab 100644
--- a/roles/jobs_cancel/README.md
+++ b/roles/jobs_cancel/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,6 +22,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_cancel_jobs`|`see below`|yes|Data structure describing jobs to cancel Described below.||
### Secure Logging Variables
diff --git a/roles/jobs_cancel/tasks/main.yml b/roles/jobs_cancel/tasks/main.yml
index c40e0ca13..e41abb5a7 100644
--- a/roles/jobs_cancel/tasks/main.yml
+++ b/roles/jobs_cancel/tasks/main.yml
@@ -9,6 +9,7 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
diff --git a/roles/labels/README.md b/roles/labels/README.md
index f64fcd9a1..51786ec4d 100644
--- a/roles/labels/README.md
+++ b/roles/labels/README.md
@@ -1,6 +1,6 @@
# controller_configuration.labels
-An Ansible role to create labels for templates on Ansible Controller.
+An Ansible role to create/update/remove labels for templates on Ansible Controller.
## Requirements
@@ -12,8 +12,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -22,6 +20,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_labels`|`see below`|yes|Data structure describing your label or labels Described below.||
### Secure Logging Variables
@@ -49,6 +48,7 @@ This also speeds up the overall role.
|`controller_configuration_labels_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_labels_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/labels/defaults/main.yml b/roles/labels/defaults/main.yml
index 703351e6b..a9c861b4c 100644
--- a/roles/labels/defaults/main.yml
+++ b/roles/labels/defaults/main.yml
@@ -3,4 +3,5 @@ controller_labels: []
controller_configuration_labels_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_labels_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_labels_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
...
diff --git a/roles/labels/meta/argument_specs.yml b/roles/labels/meta/argument_specs.yml
index 16b7033e3..a057cf09c 100644
--- a/roles/labels/meta/argument_specs.yml
+++ b/roles/labels/meta/argument_specs.yml
@@ -43,6 +43,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/labels/meta/main.yml b/roles/labels/meta/main.yml
index 0ebc16986..0947e0d49 100644
--- a/roles/labels/meta/main.yml
+++ b/roles/labels/meta/main.yml
@@ -25,4 +25,9 @@ galaxy_info:
collections:
- ansible.controller
- awx.awx
+
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/labels/tasks/main.yml b/roles/labels/tasks/main.yml
index 971d2b623..33485e2c6 100644
--- a/roles/labels/tasks/main.yml
+++ b/roles/labels/tasks/main.yml
@@ -1,5 +1,5 @@
---
-- name: Add a label to Controller
+- name: "Managing Labels"
label:
name: "{{ __controller_label_item.name | mandatory }}"
new_name: "{{ __controller_label_item.new_name | default(omit, true) }}"
@@ -12,19 +12,27 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_labels }}"
loop_control:
loop_var: __controller_label_item
+ label: "{{ __operation.verb }} the label {{ __controller_label_item.name }} to Controller"
no_log: "{{ controller_configuration_labels_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_label_job_async
changed_when: not __controller_label_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_label_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Labels | Wait for finish the Label creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_label_job_async.failed is defined and __controller_label_job_async.failed
+
+- name: "Managing Labels | Wait for finish the Labels management"
ansible.builtin.async_status:
jid: "{{ __controller_label_job_async_results_item.ansible_job_id }}"
register: __controller_label_job_async_result
@@ -34,8 +42,10 @@
loop: "{{ __controller_label_job_async.results }}"
loop_control:
loop_var: __controller_label_job_async_results_item
- when: __controller_label_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Label {{ __controller_label_job_async_results_item.__controller_label_item.name }} | Wait for finish the Label {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_label_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_labels_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_label_job_async_results_item.__controller_label_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/license/README.md b/roles/license/README.md
index 6775f1fd7..b7e2aa147 100644
--- a/roles/license/README.md
+++ b/roles/license/README.md
@@ -4,6 +4,8 @@
An Ansible Role to deploy a license on Ansible Controller.
+This will either accept a manifest file, or use redhat subscription account credentials to lookup available subscriptions and use them.
+
## Requirements
ansible-galaxy collection install -r tests/collections/requirements.yml to be installed
@@ -14,8 +16,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +24,10 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_license`|`see below`|yes|Data structure describing your license for controller, described below.||
+|`redhat_subscription_username`|""|no|Red Hat or Red Hat Satellite username to get available subscriptions. Used only for Subscription lookup implementation.|
+|`redhat_subscription_password`|""|no|Red Hat or Red Hat Satellite password to get available subscriptions. Used only for Subscription lookup implementation.|
### Secure Logging Variables
@@ -40,7 +43,11 @@ controller_configuration_license_secure_logging defaults to the value of control
## Data Structure
-### License Variables
+### Manifest vs Subscription
+
+The module and this role can use either a manifest file, or lookup the subscription on your account. Only one method is needed, provide the appropriate variables to use the either method.
+
+### License Variables for using mainfest
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
@@ -53,8 +60,19 @@ controller_configuration_license_secure_logging defaults to the value of control
|`pool_id`|""|no|str|Red Hat or Red Hat Satellite pool_id to attach to|
|`eula_accepted`|""|yes|bool|DEPRECATED since Tower 3.8 - Whether to accept the End User License Agreement for Ansible controller|
|`force`|`False`|no|bool|By default, the license manifest will only be applied if controller is currently unlicensed or trial licensed. When force=true, the license is always applied.|
+|`state`|`present`|no|str|Desired state of the resource.|
-For further details on fields see
+### License Variables for using Red Hat Subscription
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`filters`|"default values"|no|str|dict of filters to use to narrow the subscription. See example below for how to use this.|
+|`support_level`|"Self-Support"|no|str|DEPRECATED - changed to `manifest_file` (still works as an alias)|
+|`list_num`|0|no|int|List index of the subscription to use, if you want to overide the default, it is recomended to use the filters to limit the pools found.|
+|`pool_id`|""|no|str|Red Hat or Red Hat Satellite pool_id to attach to.|
+|`force`|`False`|no|bool|By default, the license will only be applied if controller is currently unlicensed or trial licensed. When force=true, the license is always applied.|
+|`use_lookup`|`False`|no|bool|Whether or not to lookup subscriptions.|
+|`state`|`present`|no|str|Desired state of the resource.|
### Standard Project Data Structure
@@ -82,7 +100,7 @@ controller_license:
## Playbook Examples
-### Standard Role Usage
+### Standard Manifest Role Usage
```yaml
---
@@ -103,6 +121,28 @@ controller_license:
- {role: infra.controller_configuration.license, when: controller_license is defined}
```
+### Standard Subscription lookup Role Usage
+
+```yaml
+---
+- name: Playbook to configure ansible controller post installation
+ hosts: localhost
+ connection: local
+ vars:
+ controller_validate_certs: false
+ controller_hostname: controller.example.com
+ controller_username: admin
+ controller_password: changeme
+ redhat_subscription_username: changeme
+ redhat_subscription_password: changeme
+ controller_license:
+ filters:
+ product_name: "Red Hat Ansible Automation Platform"
+ support_level: "Self-Support"
+ roles:
+ - {role: infra.controller_configuration.license}
+```
+
## License
[MIT](https://github.com/redhat-cop/controller_configuration#licensing)
diff --git a/roles/license/defaults/main.yml b/roles/license/defaults/main.yml
index 114c343d5..fbb93ef3b 100644
--- a/roles/license/defaults/main.yml
+++ b/roles/license/defaults/main.yml
@@ -1,3 +1,6 @@
---
controller_configuration_license_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
+_redhat_cop_license_filters:
+ product_name: Red Hat Ansible Automation Platform
+ support_level: Self-Support
...
diff --git a/roles/license/meta/argument_specs.yml b/roles/license/meta/argument_specs.yml
index f0851624b..3040dd82f 100644
--- a/roles/license/meta/argument_specs.yml
+++ b/roles/license/meta/argument_specs.yml
@@ -4,10 +4,9 @@ argument_specs:
short_description: An Ansible Role to deploy a license on Ansible Controller.
options:
- controller_labels:
+ controller_license:
description: Data structure describing your license for Controller
- type: list
- elements: dict
+ type: dict
# options:
# manifest_file:
# required: false
@@ -46,6 +45,23 @@ argument_specs:
# required: false
# type: bool
# description: By default, the license manifest will only be applied if controller is currently unlicensed or trial licensed. When force=true, the license is always applied.
+ # use_lookup:
+ # default: false
+ # required: false
+ # type: bool
+ # description: Whether or not to lookup subscriptions.
+
+ # Variables used for Liscense lookup
+ redhat_subscription_username:
+ default: None
+ required: false
+ type: str
+ description: Red Hat or Red Hat Satellite username to get available subscriptions.
+ redhat_subscription_password:
+ default: None
+ required: false
+ type: str
+ description: Red Hat or Red Hat Satellite password to get available subscriptions.
# No_log variables
controller_configuration_labels_secure_logging:
diff --git a/roles/license/tasks/main.yml b/roles/license/tasks/main.yml
index fbe491826..66fa17fe9 100644
--- a/roles/license/tasks/main.yml
+++ b/roles/license/tasks/main.yml
@@ -1,56 +1,13 @@
---
# tasks file for license role
-- name: Ensure manifest is set
- ansible.builtin.assert:
- that: controller_license.manifest_file is defined or controller_license.manifest is defined or controller_license.manifest_url is defined or controller_license.manifest_content is defined or controller_license.pool_id is defined
- fail_msg: "Must set a source for the manifest or pool. Please set 'manifest_file', 'manifest_url', 'manifest_content', or 'pool_id'"
-
-- name: Move manifest file to temporary location
- ansible.builtin.copy:
- src: "{{ controller_license.manifest_file | default(controller_license.manifest) }}"
- dest: "{{ __controller_manifest_path }}"
- mode: 0600
- when:
- - controller_license.manifest_file is defined or controller_license.manifest is defined
-
-- name: Fetch manifest from URL
- ansible.builtin.get_url:
- url: "{{ controller_license.manifest_url }}"
- dest: "{{ __controller_manifest_path }}"
- username: "{{ controller_license.manifest_username | default(omit) }}"
- password: "{{ controller_license.manifest_password | default(omit) }}"
- mode: 0600
+- name: Use manifest file
+ ansible.builtin.include_tasks: "manifest.yml"
when:
- - controller_license.manifest_url is defined
- - not controller_license.manifest_file is defined
- - not controller_license.manifest is defined
+ - controller_license.manifest_file is defined or controller_license.manifest is defined or controller_license.manifest_content is defined or controller_license.manifest_url is defined
-- name: Create manifest file from base64 encoded content
- ansible.builtin.template:
- src: controller_manifest.j2
- dest: "{{ __controller_manifest_path }}"
- mode: 0600
+- name: Use subscription pool id or subscription lookup
+ ansible.builtin.include_tasks: "subscription.yml"
when:
- - controller_license.manifest_content is defined
- - not controller_license.manifest_url is defined
- - not controller_license.manifest_file is defined
- - not controller_license.manifest is defined
-
-- name: Install the Controller license
- license:
- manifest: "{{ __controller_manifest_path | default(omit) }}"
- eula_accepted: "{{ controller_license.eula_accepted | default(omit) }}" # Depreciated only for Tower 3.8.x or lower
- pool_id: "{{ controller_license.pool_id | default(omit) }}"
- force: "{{ controller_license.force | default(omit) }}"
-
- # Role Standard Options
- controller_username: "{{ controller_username | default(omit, true) }}"
- controller_password: "{{ controller_password | default(omit, true) }}"
- controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
- controller_host: "{{ controller_hostname | default(omit, true) }}"
- controller_config_file: "{{ controller_config_file | default(omit, true) }}"
- validate_certs: "{{ controller_validate_certs | default(omit) }}"
- no_log: "{{ controller_configuration_license_secure_logging }}"
- when: controller_license is defined
+ - (redhat_subscription_username is defined and redhat_subscription_password is defined) or controller_license.pool_id is defined
...
diff --git a/roles/license/tasks/manifest.yml b/roles/license/tasks/manifest.yml
new file mode 100644
index 000000000..0f80a40d5
--- /dev/null
+++ b/roles/license/tasks/manifest.yml
@@ -0,0 +1,58 @@
+---
+# tasks file for license role - manifest
+
+- name: Ensure manifest is set
+ ansible.builtin.assert:
+ that: controller_license.manifest_file is defined or controller_license.manifest is defined or controller_license.manifest_url is defined or controller_license.manifest_content is defined or controller_license.pool_id is defined
+ fail_msg: "Must set a source for the manifest or pool. Please set 'manifest_file', 'manifest_url', 'manifest_content', or 'pool_id'"
+
+- name: Move manifest file to temporary location
+ ansible.builtin.copy:
+ src: "{{ controller_license.manifest_file | default(controller_license.manifest) }}"
+ dest: "{{ __controller_manifest_path }}"
+ mode: 0600
+ when:
+ - controller_license.manifest_file is defined or controller_license.manifest is defined
+
+- name: Fetch manifest from URL
+ ansible.builtin.get_url:
+ url: "{{ controller_license.manifest_url }}"
+ dest: "{{ __controller_manifest_path }}"
+ username: "{{ controller_license.manifest_username | default(omit) }}"
+ password: "{{ controller_license.manifest_password | default(omit) }}"
+ mode: 0600
+ when:
+ - controller_license.manifest_url is defined
+ - not controller_license.manifest_file is defined
+ - not controller_license.manifest is defined
+
+- name: Create manifest file from base64 encoded content
+ ansible.builtin.template:
+ src: controller_manifest.j2
+ dest: "{{ __controller_manifest_path }}"
+ mode: 0600
+ when:
+ - controller_license.manifest_content is defined
+ - not controller_license.manifest_url is defined
+ - not controller_license.manifest_file is defined
+ - not controller_license.manifest is defined
+
+- name: Install the Controller license
+ license:
+ manifest: "{{ __controller_manifest_path | default(omit) }}"
+ eula_accepted: "{{ controller_license.eula_accepted | default(omit) }}" # Depreciated only for Tower 3.8.x or lower
+ pool_id: "{{ controller_license.pool_id | default(omit) }}"
+ force: "{{ controller_license.force | default(omit) }}"
+ state: "{{ controller_license.state | default(omit) }}"
+
+ # Role Standard Options
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ no_log: "{{ controller_configuration_license_secure_logging }}"
+ when: controller_license is defined
+...
diff --git a/roles/license/tasks/subscription.yml b/roles/license/tasks/subscription.yml
new file mode 100644
index 000000000..e1d8ab1ac
--- /dev/null
+++ b/roles/license/tasks/subscription.yml
@@ -0,0 +1,38 @@
+---
+# tasks file for license role - Subscription
+
+- name: Get subscriptions with a filter
+ subscriptions:
+ username: "{{ redhat_subscription_username }}"
+ password: "{{ redhat_subscription_password }}"
+ filters: "{{ controller_license.filters | default(_redhat_cop_license_filters) }}"
+ # Role Standard Options
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ register: subscription
+ when:
+ - "'use_lookup' in controller_license"
+ - controller_license.use_lookup
+
+- name: Install the Controller license
+ license:
+ pool_id: "{{ controller_license.pool_id | default(subscription.subscriptions[(controller_license.list_num | default(0))].pool_id) }}"
+ force: "{{ controller_license.force | default(omit) }}"
+ state: "{{ controller_license.state | default(omit) }}"
+
+ # Role Standard Options
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ no_log: "{{ controller_configuration_license_secure_logging }}"
+ when: controller_license is defined
+...
diff --git a/roles/license/tests/config/license.yml b/roles/license/tests/config/license.yml
index bdbae5e58..6dcca8391 100644
--- a/roles/license/tests/config/license.yml
+++ b/roles/license/tests/config/license.yml
@@ -3,5 +3,4 @@ controller_license:
manifest_file: "/tmp/my_tower.zip"
# manifest_url: https://www.ansible.com/hubfs/Logo-Red_Hat-Ansible-A-Reverse-SVG.svg
# manifest_content: "aGVsbG8gd29ybGQ="
- eula_accepted: true
...
diff --git a/roles/license/tests/test.yml b/roles/license/tests/test.yml
index 0f256fcba..5d94b1388 100644
--- a/roles/license/tests/test.yml
+++ b/roles/license/tests/test.yml
@@ -8,6 +8,8 @@
controller_hostname: controller.example.com
controller_username: admin
controller_password: changeme
+ redhat_subscription_username: changeme
+ redhat_subscription_password: changeme
collections:
- awx.awx
diff --git a/roles/notification_templates/README.md b/roles/notification_templates/README.md
index 18de29298..f5c8fbb12 100644
--- a/roles/notification_templates/README.md
+++ b/roles/notification_templates/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to add notification templates on Ansible Controller.
+An Ansible Role to add/update/remove notification templates on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_notifications`|`see below`|yes|Data structure describing your notification entries described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_notifications`|`see below`|yes|Data structure describing your notification entries described below. Alias: notification_templates ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_notifications_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_notifications_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_notification_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_notification_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,7 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`name`|""|yes|str|The name of the notification.|
-|`new_name`|""|yes|str|Setting this option will change the existing name (looked up via the name field.|
+|`new_name`|""|yes|str|Setting this option will change the existing name (looked up via the name field).|
|`copy_from`|""|no|str|Name or id to copy the Notification template from. This will copy an existing notification and change any parameters supplied.|
|`description`|""|no|str|The description of the notification.|
|`organization`|""|no|str|The organization applicable to the notification.|
diff --git a/roles/notification_templates/defaults/main.yml b/roles/notification_templates/defaults/main.yml
index a88d71a34..40d9fcefb 100644
--- a/roles/notification_templates/defaults/main.yml
+++ b/roles/notification_templates/defaults/main.yml
@@ -4,4 +4,6 @@ controller_notifications: []
controller_configuration_notifications_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_notifications_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_notifications_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_notifications_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/notification_templates/meta/argument_specs.yml b/roles/notification_templates/meta/argument_specs.yml
index 9950fc4db..4a2408034 100644
--- a/roles/notification_templates/meta/argument_specs.yml
+++ b/roles/notification_templates/meta/argument_specs.yml
@@ -64,6 +64,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
controller_configuration_notification_templates_secure_logging:
diff --git a/roles/notification_templates/meta/main.yml b/roles/notification_templates/meta/main.yml
index b4aafd405..03fa67280 100644
--- a/roles/notification_templates/meta/main.yml
+++ b/roles/notification_templates/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/notification_templates/tasks/main.yml b/roles/notification_templates/tasks/main.yml
index 9431c1825..e837964da 100644
--- a/roles/notification_templates/tasks/main.yml
+++ b/roles/notification_templates/tasks/main.yml
@@ -1,14 +1,14 @@
---
-- name: Add Controller notifications
+- name: "Managing Controller Notifications"
notification_template:
name: "{{ __controller_notification_item.name | mandatory }}"
new_name: "{{ __controller_notification_item.new_name | default(omit, true) }}"
copy_from: "{{ __controller_notification_item.copy_from | default(omit, true) }}"
- description: "{{ __controller_notification_item.description | default(omit, true) }}"
- organization: "{{ __controller_notification_item.organization.name | default(__controller_notification_item.organization) }}"
- notification_type: "{{ __controller_notification_item.notification_type | default(omit, true) }}"
- notification_configuration: "{{ __controller_notification_item.notification_configuration | default(omit, true) }}"
- messages: "{{ __controller_notification_item.messages | default(omit, true) | regex_replace('[ ]{2,}', '') }}"
+ description: "{{ __controller_notification_item.description | default(('' if controller_configuration_notifications_enforce_defaults else omit), true) }}"
+ organization: "{{ __controller_notification_item.organization.name | default(__controller_notification_item.organization) | mandatory }}"
+ notification_type: "{{ __controller_notification_item.notification_type | default(omit, true) | mandatory }}"
+ notification_configuration: "{{ __controller_notification_item.notification_configuration | default(({} if controller_configuration_notifications_enforce_defaults else omit), true) }}"
+ messages: "{{ __controller_notification_item.messages | default(({} if controller_configuration_notifications_enforce_defaults else omit), true) | regex_replace('[ ]{2,}', '') }}"
state: "{{ __controller_notification_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
@@ -16,20 +16,28 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_notifications }}"
+ loop: "{{ notification_templates if notification_templates is defined else controller_notifications }}"
loop_control:
loop_var: __controller_notification_item
+ label: "{{ __operation.verb }} Controller notification {{ __controller_notification_item.name }}"
no_log: "{{ controller_configuration_notifications_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_notification_job_async
changed_when: not __controller_notification_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_notification_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure notifications | Wait for finish the notifications creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_notification_job_async.failed is defined and __controller_notification_job_async.failed
+
+- name: "Managing Notifications | Wait for finish the Notifications management"
ansible.builtin.async_status:
jid: "{{ __controller_notification_job_async_results_item.ansible_job_id }}"
register: __controller_notification_job_async_result
@@ -39,8 +47,10 @@
loop: "{{ __controller_notification_job_async.results }}"
loop_control:
loop_var: __controller_notification_job_async_results_item
- when: __controller_notification_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} notification {{ __controller_notification_job_async_results_item.__controller_notification_item.name }} | Wait for finish the notifications {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_notification_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_notifications_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_notification_job_async_results_item.__controller_notification_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/notification_templates/tests/configs/notifications.yml b/roles/notification_templates/tests/configs/notifications.yml
index 3860939b8..00ae4d5dc 100644
--- a/roles/notification_templates/tests/configs/notifications.yml
+++ b/roles/notification_templates/tests/configs/notifications.yml
@@ -1,7 +1,7 @@
---
-controller_notification_templates:
+controller_notifications:
- name: Email notification
- description: Send out emails for Controller jobs
+ # description: Send out emails for Controller jobs
organization: Default
notification_type: email
notification_configuration:
@@ -9,7 +9,9 @@ controller_notification_templates:
recipients:
- admin@example.com
sender: tower0@example.com
- port: '25'
+ port: 25
username: ''
password: ''
+ use_tls: false
+ use_ssl: false
...
diff --git a/roles/notification_templates/tests/test.yml b/roles/notification_templates/tests/test.yml
index 48f311ade..2e1df99b9 100644
--- a/roles/notification_templates/tests/test.yml
+++ b/roles/notification_templates/tests/test.yml
@@ -19,5 +19,5 @@
extensions: ["yml"]
roles:
- - {role: ../.., when: controller_notification_templates is defined}
+ - {role: ../.., when: controller_notifications is defined}
...
diff --git a/roles/object_diff/defaults/main.yml b/roles/object_diff/defaults/main.yml
index 483b3c949..f910020f7 100644
--- a/roles/object_diff/defaults/main.yml
+++ b/roles/object_diff/defaults/main.yml
@@ -38,7 +38,6 @@ controller_configuration_object_diff_tasks:
- {name: user_accounts, var: controller_user_accounts, tags: users}
- {name: groups, var: controller_groups, tags: groups}
- {name: hosts, var: controller_hosts, tags: hosts}
- - {name: instance_groups, var: controller_instance_groups, tags: instance_groups}
- {name: applications, var: controller_applications, tags: applications}
- {name: execution_environments, var: controller_execution_environments, tags: execution_environments}
- {name: inventory_sources, var: controller_inventory_sources, tags: inventory_sources}
@@ -48,9 +47,11 @@ controller_configuration_object_diff_tasks:
- {name: credentials, var: controller_credentials, tags: credentials}
- {name: credential_types, var: controller_credential_types, tags: credential_types}
- {name: organizations, var: controller_organizations, tags: organizations}
+ - {name: instance_groups, var: controller_instance_groups, tags: instance_groups}
controller_configuration_object_diff_secure_logging: "{{ controller_configuration_secure_logging | default(true) }}"
controller_api_version: "v2"
+include_present_state: false
...
diff --git a/roles/object_diff/tasks/applications.yml b/roles/object_diff/tasks/applications.yml
index 28bf86932..ad337a871 100644
--- a/roles/object_diff/tasks/applications.yml
+++ b/roles/object_diff/tasks/applications.yml
@@ -9,17 +9,17 @@
- name: "Get the API list of all Applications in Organization {{ orgs }}"
ansible.builtin.set_fact:
__controller_api_applications: "{{ query(controller_api_plugin, 'applications',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
- name: "Find the difference of Application between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __applications_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_applications, compare_list=controller_applications,
- with_present=false, set_absent=true)
- }}"
+ __applications_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_applications, compare_list=controller_applications,
+ with_present=include_present_state, set_absent=true) | flatten
+ }}"
- name: "Set application's list to be configured"
ansible.builtin.set_fact:
diff --git a/roles/object_diff/tasks/credential_types.yml b/roles/object_diff/tasks/credential_types.yml
index 5d800d013..8b42e43de 100644
--- a/roles/object_diff/tasks/credential_types.yml
+++ b/roles/object_diff/tasks/credential_types.yml
@@ -22,9 +22,10 @@
- name: "Find the difference of Credential Types between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __credential_types_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_credential_types, compare_list=controller_credential_types,
- with_present=false, set_absent=true) }}"
+ __credential_types_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_credential_types, compare_list=controller_credential_types,
+ with_present=include_present_state, set_absent=true) | flatten
+ }}"
- name: "Set credential's list to be configured"
ansible.builtin.set_fact:
diff --git a/roles/object_diff/tasks/credentials.yml b/roles/object_diff/tasks/credentials.yml
index ca5321b3a..8929bf44e 100644
--- a/roles/object_diff/tasks/credentials.yml
+++ b/roles/object_diff/tasks/credentials.yml
@@ -19,9 +19,9 @@
- name: "Find the difference of Credentials between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __credentials_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_credentials, compare_list=controller_credentials,
- with_present=false, set_absent=true)
+ __credentials_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_credentials, compare_list=controller_credentials,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set credential's list to be configured"
diff --git a/roles/object_diff/tasks/execution_environments.yml b/roles/object_diff/tasks/execution_environments.yml
index c63c24cb0..b6e0fb686 100644
--- a/roles/object_diff/tasks/execution_environments.yml
+++ b/roles/object_diff/tasks/execution_environments.yml
@@ -1,27 +1,30 @@
---
-- name: Get the organization ID
- ansible.builtin.set_fact:
- __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
- }}"
+- name: "Block to be executed only when connected against an AAP instance (not Tower)"
+ when: is_aap
+ block:
+ - name: Get the organization ID
+ ansible.builtin.set_fact:
+ __controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ }}"
-- name: "Get the API list of all Execution Environments in Organization {{ orgs }}"
- ansible.builtin.set_fact:
- __controller_api_execution_environments: "{{ query(controller_api_plugin, 'execution_environments',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ - name: "Get the API list of all Execution Environments in Organization {{ orgs }}"
+ ansible.builtin.set_fact:
+ __controller_api_execution_environments: "{{ query(controller_api_plugin, 'execution_environments',
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
-- name: "Find the difference of Execution Environment between what is on the Controller versus CasC on SCM"
- ansible.builtin.set_fact:
- __execution_environments_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_execution_environments, compare_list=controller_execution_environments,
- with_present=false, set_absent=true)
- }}"
+ - name: "Find the difference of Execution Environment between what is on the Controller versus CasC on SCM"
+ ansible.builtin.set_fact:
+ __execution_environments_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_execution_environments, compare_list=controller_execution_environments,
+ with_present=include_present_state, set_absent=true) | flatten
+ }}"
-- name: "Set execution_environment's list to be configured"
- ansible.builtin.set_fact:
- controller_execution_environments: "{{ __execution_environments_difference }}"
+ - name: "Set execution_environment's list to be configured"
+ ansible.builtin.set_fact:
+ controller_execution_environments: "{{ __execution_environments_difference }}"
...
diff --git a/roles/object_diff/tasks/groups.yml b/roles/object_diff/tasks/groups.yml
index 7104f3f37..81fd8041d 100644
--- a/roles/object_diff/tasks/groups.yml
+++ b/roles/object_diff/tasks/groups.yml
@@ -36,10 +36,10 @@
block:
- name: "Find the difference of Groups between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __groups_difference: "{{ lookup(controller_role_plugin,
+ __groups_difference: "{{ query(controller_role_plugin,
query_params={'summary_fields.inventory.organization_id': controller_organization_id.id},
api_list=__controller_api_groups, compare_list=controller_groups,
- with_present=false, set_absent=true)
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set the inventory key at the correct place"
diff --git a/roles/object_diff/tasks/hosts.yml b/roles/object_diff/tasks/hosts.yml
index aeadd54e9..31d898c7d 100644
--- a/roles/object_diff/tasks/hosts.yml
+++ b/roles/object_diff/tasks/hosts.yml
@@ -14,8 +14,7 @@
'has_inventory_sources': 'false',
'not__total_hosts': '0',
'not__kind': 'smart'},
- host=controller_hostname, username=controller_username,
- oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
return_all=true, max_objects=query_controller_api_max_objects)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -37,10 +36,10 @@
block:
- name: "Find the difference of Hosts between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __hosts_difference: "{{ lookup(controller_role_plugin,
+ __hosts_difference: "{{ query(controller_role_plugin,
query_params={'summary_fields.inventory.organization_id': controller_organization_id.id},
api_list=__controller_api_hosts, compare_list=controller_hosts,
- with_present=false, set_absent=true)
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set the inventory key at the correct place"
diff --git a/roles/object_diff/tasks/instance_groups.yml b/roles/object_diff/tasks/instance_groups.yml
index 8acc1590f..cad212783 100644
--- a/roles/object_diff/tasks/instance_groups.yml
+++ b/roles/object_diff/tasks/instance_groups.yml
@@ -1,9 +1,8 @@
---
- name: "Get the current controller user to determine if it is super-admin"
ansible.builtin.set_fact:
- __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'users',
- query_params={'username': controller_username},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me',
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
- name: "Instance Group differences (block)"
@@ -13,18 +12,18 @@
- name: "Get the API list of all instance_groups"
ansible.builtin.set_fact:
__controller_api_instance_groups: "{{ query(controller_api_plugin, 'instance_groups',
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
- name: "Find the difference of Instance Groups between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __instance_groups_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_instance_groups,
- compare_list=controller_instance_groups,
- with_present=false,
- set_absent=true)
- }}"
+ __instance_groups_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_instance_groups,
+ compare_list=controller_instance_groups,
+ with_present=include_present_state,
+ set_absent=true) | flatten
+ }}"
- name: "Sets the difference of Instance Groups between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
diff --git a/roles/object_diff/tasks/inventories.yml b/roles/object_diff/tasks/inventories.yml
index f546e237b..e407bf36b 100644
--- a/roles/object_diff/tasks/inventories.yml
+++ b/roles/object_diff/tasks/inventories.yml
@@ -18,9 +18,9 @@
- name: "Find the difference of Inventories between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __inventories_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_inventories, compare_list=controller_inventories,
- with_present=false, set_absent=true)
+ __inventories_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_inventories, compare_list=controller_inventories,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set inventores' list to be configured"
diff --git a/roles/object_diff/tasks/inventory_sources.yml b/roles/object_diff/tasks/inventory_sources.yml
index 7e993f08a..f1cde6c25 100644
--- a/roles/object_diff/tasks/inventory_sources.yml
+++ b/roles/object_diff/tasks/inventory_sources.yml
@@ -18,10 +18,10 @@
- name: "Find the difference of Inventory Sources between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __inventory_sources_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_inventory_sources,
- compare_list=controller_inventory_sources,
- with_present=false, set_absent=true)
+ __inventory_sources_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_inventory_sources,
+ compare_list=controller_inventory_sources,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set inventory_sources' list to be configured"
diff --git a/roles/object_diff/tasks/job_templates.yml b/roles/object_diff/tasks/job_templates.yml
index 9926f1e26..84b8fc577 100644
--- a/roles/object_diff/tasks/job_templates.yml
+++ b/roles/object_diff/tasks/job_templates.yml
@@ -2,8 +2,8 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -18,9 +18,9 @@
- name: "Find the difference of Job Templates between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __job_templates_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_job_templates, compare_list=controller_templates,
- with_present=false, set_absent=true)
+ __job_templates_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_job_templates, compare_list=controller_templates,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set job_template's list to be configured"
diff --git a/roles/object_diff/tasks/main.yml b/roles/object_diff/tasks/main.yml
index 12d316a54..6eb0a1e21 100644
--- a/roles/object_diff/tasks/main.yml
+++ b/roles/object_diff/tasks/main.yml
@@ -59,12 +59,13 @@
tags:
- always
-- name: "Include Tasks to get OBJECT DIFF {{ __task_diff.name }}"
+- name: "Include Tasks to get OBJECT DIFF"
ansible.builtin.include_tasks: "{{ __task_diff.name }}.yml"
args:
apply:
tags: "{{ __task_diff.tags }}"
- tags: always
+ tags:
+ - always
loop: "{{ controller_configuration_object_diff_tasks }}"
loop_control:
loop_var: __task_diff
diff --git a/roles/object_diff/tasks/notification_templates.yml b/roles/object_diff/tasks/notification_templates.yml
index b7ea000a5..4308c6fd0 100644
--- a/roles/object_diff/tasks/notification_templates.yml
+++ b/roles/object_diff/tasks/notification_templates.yml
@@ -2,24 +2,24 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
- name: "Get the API list of all Notification Templates in Organization {{ orgs }}"
ansible.builtin.set_fact:
__controller_api_notification_templates: "{{ query(controller_api_plugin, 'notification_templates',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
- name: "Find the difference of Notification Template between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __notification_templates_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_notification_templates, compare_list=controller_notifications,
- with_present=false, set_absent=true)
- }}"
+ __notification_templates_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_notification_templates, compare_list=controller_notifications,
+ with_present=include_present_state, set_absent=true) | flatten
+ }}"
- name: "Set notification_template's list to be configured"
ansible.builtin.set_fact:
diff --git a/roles/object_diff/tasks/organizations.yml b/roles/object_diff/tasks/organizations.yml
index e88c1666e..7497eb81e 100644
--- a/roles/object_diff/tasks/organizations.yml
+++ b/roles/object_diff/tasks/organizations.yml
@@ -1,8 +1,7 @@
---
- name: "Get the current controller user to determine if it is super-admin"
ansible.builtin.set_fact:
- __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'users',
- query_params={'username': controller_username},
+ __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me',
host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -21,9 +20,9 @@
- name: "Find the difference of Organizations between what is on the Controller versus curated list."
ansible.builtin.set_fact:
- __organizations_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_organizations, compare_list=controller_organizations,
- with_present=false, set_absent=true)
+ __organizations_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_organizations, compare_list=controller_organizations,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set list __list_empty_orgs when protect_not_empty_orgs"
diff --git a/roles/object_diff/tasks/projects.yml b/roles/object_diff/tasks/projects.yml
index 3b119ab6c..b9e338055 100644
--- a/roles/object_diff/tasks/projects.yml
+++ b/roles/object_diff/tasks/projects.yml
@@ -2,25 +2,25 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
- name: "Get the API list of all Projects in Organization {{ orgs }}"
ansible.builtin.set_fact:
__controller_api_projects: "{{ query(controller_api_plugin, 'projects',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
- name: "Find the difference of Project between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __projects_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_projects, compare_list=controller_projects,
- with_present=false, set_absent=true)
+ __projects_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_projects, compare_list=controller_projects,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set project's list to be configured"
diff --git a/roles/object_diff/tasks/roles.yml b/roles/object_diff/tasks/roles.yml
index 095161f21..97d56dabc 100644
--- a/roles/object_diff/tasks/roles.yml
+++ b/roles/object_diff/tasks/roles.yml
@@ -1,9 +1,8 @@
---
- name: "Get the current controller user to determine if it is super-admin"
ansible.builtin.set_fact:
- __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'users',
- query_params={'username': controller_username},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me',
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -12,16 +11,17 @@
- __controller_api_current_user_check_is_admin.is_superuser
block:
- - name: "Get the API list of all roles" # noqa jinja[spacing]
+ - name: "Get the API list of all roles"
ansible.builtin.set_fact:
+ # noqa jinja[spacing]
__controller_api_roles: "{{ (__controller_api_roles | default([])) + [{
'users': current_users,
'teams': current_teams,
'name': current_role.name,
'role': current_role.name,
'type': current_role.type,
- 'resource_type': (current_role.summary_fields.resource_type|default('no_resource_type')),
- (current_role.summary_fields.resource_type|default('no_resource_type')): (current_role.summary_fields.resource_name|default('no_resource_name'))
+ 'resource_type': (current_role.summary_fields.resource_type | default('no_resource_type')),
+ (current_role.summary_fields.resource_type | default('no_resource_type')): (current_role.summary_fields.resource_name | default('no_resource_name'))
}]
}}"
vars:
@@ -44,18 +44,18 @@
- name: "Explode the roles for users"
ansible.builtin.set_fact:
__full_controller_api_roles: "{{ (__full_controller_api_roles | default([])) + [item.0 | combine({'user': item.1})] }}"
- loop: "{{ (__controller_api_roles | subelements('users')) }}"
+ loop: "{{ (__controller_api_roles | default([]) | subelements('users', skip_missing=true)) }}"
- name: "Explode the roles for teams"
ansible.builtin.set_fact:
__full_controller_api_roles: "{{ (__full_controller_api_roles | default([])) + [item.0 | combine({'team': item.1})] }}"
- loop: "{{ (__controller_api_roles | subelements('teams')) }}"
+ loop: "{{ (__controller_api_roles | default([]) | subelements('teams', skip_missing=true)) }}"
- name: "Find the difference of Roles between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __roles_difference: "{{ lookup(controller_role_plugin,
- api_list=__full_controller_api_roles, compare_list=controller_roles,
- with_present=false, set_absent=true)
+ __roles_difference: "{{ query(controller_role_plugin,
+ api_list=__full_controller_api_roles, compare_list=controller_roles,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Sets differences between Roles what is on the Controller versus CasC on SCM"
diff --git a/roles/object_diff/tasks/schedules.yml b/roles/object_diff/tasks/schedules.yml
index fe2994186..8deffd283 100644
--- a/roles/object_diff/tasks/schedules.yml
+++ b/roles/object_diff/tasks/schedules.yml
@@ -2,8 +2,8 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
- name: "Get the API list of all WF and Job Templates in Organization {{ orgs }}"
@@ -14,10 +14,10 @@
return_all=true, max_objects=query_controller_api_max_objects)
}}"
__controller_api_workflow_job_templates: "{{ query(controller_api_plugin, 'workflow_job_templates',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
- name: "Get WF and JT IDs" # noqa jinja[spacing]
@@ -27,9 +27,9 @@
- name: "Get the API list of all Schedules"
ansible.builtin.set_fact:
__controller_api_schedules_prefilter: "{{ query(controller_api_plugin, 'schedules',
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
- }}"
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
+ }}"
- name: "Get the API list of all Schedules in Organization {{ orgs }}"
ansible.builtin.set_fact:
@@ -37,10 +37,10 @@
- name: "Find the difference of Schedule between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __schedules_difference: "{{ lookup(controller_role_plugin,
+ __schedules_difference: "{{ query(controller_role_plugin,
api_list=__controller_api_schedules, compare_list=controller_schedules,
- with_present=false, set_absent=true)
- }}"
+ with_present=include_present_state, set_absent=true) | flatten
+ }}"
- name: "Set schedule's list to be configured"
ansible.builtin.set_fact:
diff --git a/roles/object_diff/tasks/teams.yml b/roles/object_diff/tasks/teams.yml
index d1abf599f..70a7d5b5f 100644
--- a/roles/object_diff/tasks/teams.yml
+++ b/roles/object_diff/tasks/teams.yml
@@ -1,9 +1,8 @@
---
- name: "Get the current controller user to determine if it is super-admin"
ansible.builtin.set_fact:
- __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'users',
- query_params={'username': controller_username},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me',
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -14,8 +13,8 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -30,11 +29,11 @@
- name: "Find the difference of Teams between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __teams_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_teams,
- compare_list=controller_teams,
- with_present=false,
- set_absent=true)
+ __teams_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_teams,
+ compare_list=controller_teams,
+ with_present=include_present_state,
+ set_absent=true) | flatten
}}"
- name: "Sets the difference of Teams between what is on the Controller versus CasC on SCM"
diff --git a/roles/object_diff/tasks/user_accounts.yml b/roles/object_diff/tasks/user_accounts.yml
index 1bfb32e5a..b8109dd66 100644
--- a/roles/object_diff/tasks/user_accounts.yml
+++ b/roles/object_diff/tasks/user_accounts.yml
@@ -2,9 +2,8 @@
# tasks file for controller_ldap_settings
- name: "Get the current controller user to determine if it is super-admin"
ansible.builtin.set_fact:
- __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'users',
- query_params={'username': controller_username},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ __controller_api_current_user_check_is_admin: "{{ lookup(controller_api_plugin, 'me',
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
@@ -36,9 +35,9 @@
block:
- name: "Find the difference of User Accounts between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __user_accounts_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_user_accounts, compare_list=controller_user_accounts,
- with_present=false, set_absent=true)
+ __user_accounts_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_user_accounts, compare_list=controller_user_accounts,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
diff --git a/roles/object_diff/tasks/workflow_job_templates.yml b/roles/object_diff/tasks/workflow_job_templates.yml
index 2f3c93c8a..cf7f05ffa 100644
--- a/roles/object_diff/tasks/workflow_job_templates.yml
+++ b/roles/object_diff/tasks/workflow_job_templates.yml
@@ -2,26 +2,26 @@
- name: Get the organization ID
ansible.builtin.set_fact:
__controller_organization_id: "{{ lookup(controller_api_plugin, 'organizations',
- query_params={'name': orgs},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
+ query_params={'name': orgs},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
- name: "Get the API list of all Workflow Job Templates"
ansible.builtin.set_fact:
__controller_api_workflow_job_templates: "{{ query(controller_api_plugin, 'workflow_job_templates',
- query_params={'organization': __controller_organization_id.id},
- host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
- return_all=true, max_objects=query_controller_api_max_objects)
+ query_params={'organization': __controller_organization_id.id},
+ host=controller_hostname, oauth_token=controller_oauthtoken, verify_ssl=controller_validate_certs,
+ return_all=true, max_objects=query_controller_api_max_objects)
}}"
no_log: "{{ controller_configuration_object_diff_secure_logging }}"
- name: "Find the difference of Workflow Job Templates between what is on the Controller versus CasC on SCM"
ansible.builtin.set_fact:
- __workflow_job_templates_difference: "{{ lookup(controller_role_plugin,
- api_list=__controller_api_workflow_job_templates,
- compare_list=controller_workflows,
- with_present=false, set_absent=true)
+ __workflow_job_templates_difference: "{{ query(controller_role_plugin,
+ api_list=__controller_api_workflow_job_templates,
+ compare_list=controller_workflows,
+ with_present=include_present_state, set_absent=true) | flatten
}}"
- name: "Set job_template's list to be configured"
diff --git a/roles/object_diff/tests/.gitignore b/roles/object_diff/tests/.gitignore
new file mode 100644
index 000000000..9bcaba703
--- /dev/null
+++ b/roles/object_diff/tests/.gitignore
@@ -0,0 +1,3 @@
+collections
+.vault_password_file
+vault.yml
diff --git a/roles/object_diff/tests/drop_diff.yml b/roles/object_diff/tests/drop_diff.yml
index d76a29a71..46e371e7c 100644
--- a/roles/object_diff/tests/drop_diff.yml
+++ b/roles/object_diff/tests/drop_diff.yml
@@ -40,6 +40,7 @@
controller_configuration_dispatcher_roles:
- {role: workflow_job_templates, var: controller_workflows, tags: workflow_job_templates}
- {role: job_templates, var: controller_templates, tags: job_templates}
+ - {role: roles, var: controller_roles, tags: roles}
- {role: teams, var: controller_teams, tags: teams}
- {role: users, var: controller_user_accounts, tags: users}
- {role: groups, var: controller_groups, tags: inventories}
@@ -62,4 +63,6 @@
validate_certs: "{{ controller_validate_certs }}"
status_code: 204
when: controller_oauthtoken_url is defined
+ tags:
+ - always
...
diff --git a/roles/object_diff/tests/object_diff.yml b/roles/object_diff/tests/object_diff.yml
index b6cd9efa7..bd2089c66 100644
--- a/roles/object_diff/tests/object_diff.yml
+++ b/roles/object_diff/tests/object_diff.yml
@@ -46,4 +46,6 @@
validate_certs: "{{ controller_validate_certs }}"
status_code: 204
when: controller_oauthtoken_url is defined
+ tags:
+ - always
...
diff --git a/roles/organizations/README.md b/roles/organizations/README.md
index 9a43a43c1..e91f11aca 100644
--- a/roles/organizations/README.md
+++ b/roles/organizations/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Organizations on Ansible Controller.
+An Ansible Role to create/update/remove Organizations on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_organizations`|`see below`|yes|Data structure describing your organization or organizations Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_organizations`|`see below`|yes|Data structure describing your organization or organizations Described below. Alias: organizations ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_organizations_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_organizations_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_organizations_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_organizations_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Organization Data Structure
diff --git a/roles/organizations/defaults/main.yml b/roles/organizations/defaults/main.yml
index ab468ed1a..d6235a90f 100644
--- a/roles/organizations/defaults/main.yml
+++ b/roles/organizations/defaults/main.yml
@@ -3,6 +3,8 @@ controller_organizations: []
controller_configuration_organizations_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_organizations_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_organizations_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_organizations_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
assign_galaxy_credentials_to_org: true
assign_default_ee_to_org: true
...
diff --git a/roles/organizations/meta/argument_specs.yml b/roles/organizations/meta/argument_specs.yml
index c3e91de82..c8dfbfae8 100644
--- a/roles/organizations/meta/argument_specs.yml
+++ b/roles/organizations/meta/argument_specs.yml
@@ -91,6 +91,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/organizations/meta/main.yml b/roles/organizations/meta/main.yml
index 457622ad8..904560007 100644
--- a/roles/organizations/meta/main.yml
+++ b/roles/organizations/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/organizations/tasks/main.yml b/roles/organizations/tasks/main.yml
index 1ea03e7a1..c1e75215e 100644
--- a/roles/organizations/tasks/main.yml
+++ b/roles/organizations/tasks/main.yml
@@ -1,38 +1,46 @@
---
-- name: Add organizations
+- name: "Managing Organizations"
organization:
name: "{{ __controller_organizations_item.name | mandatory }}"
- description: "{{ __controller_organizations_item.description | default(omit, true) }}"
+ description: "{{ __controller_organizations_item.description | default(('' if controller_configuration_organizations_enforce_defaults else omit), true) }}"
custom_virtualenv: "{{ __controller_organizations_item.custom_virtualenv | default(omit, true) }}"
max_hosts: "{{ __controller_organizations_item.max_hosts | default(omit, true) }}"
- instance_groups: "{{ __controller_organizations_item.instance_groups | default(omit, true) }}"
- default_environment: "{{ (__controller_organizations_item.default_environment | default(omit)) if (assign_default_ee_to_org is defined and assign_default_ee_to_org) else omit }}"
- galaxy_credentials: "{{ (__controller_organizations_item.galaxy_credentials | default(omit)) if (assign_galaxy_credentials_to_org is defined and assign_galaxy_credentials_to_org) else omit }}"
- notification_templates_approvals: "{{ __controller_organizations_item.notification_templates_approvals | default(__controller_organizations_item.related.notification_templates_approvals | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_started: "{{ __controller_organizations_item.notification_templates_started | default(__controller_organizations_item.related.notification_templates_started | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_success: "{{ __controller_organizations_item.notification_templates_success | default(__controller_organizations_item.related.notification_templates_success | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_error: "{{ __controller_organizations_item.notification_templates_error | default(__controller_organizations_item.related.notification_templates_error | default([]) | map(attribute='name') | list) | default(omit, true) }}"
+ instance_groups: "{{ __controller_organizations_item.instance_groups | default(([] if controller_configuration_organizations_enforce_defaults else omit), true) }}"
+ default_environment: "{{ (__controller_organizations_item.default_environment.name | default(__controller_organizations_item.default_environment | default(__controller_organizations_item.execution_environment | default(omit)))) if (assign_default_ee_to_org is defined and assign_default_ee_to_org) else omit }}"
+ galaxy_credentials: "{{ (__controller_organizations_item.galaxy_credentials | default(([] if controller_configuration_organizations_enforce_defaults else omit), true)) if (assign_galaxy_credentials_to_org is defined and assign_galaxy_credentials_to_org) else omit }}"
+ notification_templates_approvals: "{{ (__controller_organizations_item.related.notification_templates_approvals | map(attribute='name') | list if __controller_organizations_item.related.notification_templates_approvals is defined) | default(__controller_organizations_item.notification_templates_approvals) | default(([] if controller_configuration_organizations_enforce_defaults else omit), true) }}"
+ notification_templates_started: "{{ (__controller_organizations_item.related.notification_templates_started | map(attribute='name') | list if __controller_organizations_item.related.notification_templates_started is defined) | default(__controller_organizations_item.notification_templates_started) | default(([] if controller_configuration_organizations_enforce_defaults else omit), true) }}"
+ notification_templates_success: "{{ (__controller_organizations_item.related.notification_templates_success | map(attribute='name') | list if __controller_organizations_item.related.notification_templates_success is defined) | default(__controller_organizations_item.notification_templates_success) | default(([] if controller_configuration_organizations_enforce_defaults else omit), true) }}"
+ notification_templates_error: "{{ (__controller_organizations_item.related.notification_templates_error | map(attribute='name') | list if __controller_organizations_item.related.notification_templates_error is defined) | default(__controller_organizations_item.notification_templates_error) | default(([] if controller_configuration_organizations_enforce_defaults else omit), true) }}"
state: "{{ __controller_organizations_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_organizations }}"
+ loop: "{{ organizations if organizations is defined else controller_organizations }}"
loop_control:
loop_var: __controller_organizations_item
+ label: "{{ __operation.verb }} organization {{ __controller_organizations_item.name }}"
no_log: "{{ controller_configuration_organizations_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __organizations_job_async
changed_when: not __organizations_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_organizations_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Organizations | Wait for finish the organization creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __organizations_job_async.failed is defined and __organizations_job_async.failed
+
+- name: "Managing Controller Organizations | Wait for finish the Organizations management"
ansible.builtin.async_status:
jid: "{{ __organizations_job_async_results_item.ansible_job_id }}"
register: __organizations_job_async_result
@@ -42,8 +50,10 @@
loop: "{{ __organizations_job_async.results }}"
loop_control:
loop_var: __organizations_job_async_results_item
- when: __organizations_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Controller Organization {{ __organizations_job_async_results_item.__controller_organizations_item.name }} | Wait for finish the organization {{ __operation.action }}"
+ when: not ansible_check_mode and __organizations_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_organizations_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__organizations_job_async_results_item.__controller_organizations_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/project_update/README.md b/roles/project_update/README.md
index 202a9d2c5..5812648f5 100644
--- a/roles/project_update/README.md
+++ b/roles/project_update/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,8 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_projects`|`see below`|yes|Data structure describing the project to update Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_projects`|`see below`|yes|Data structure describing the project to update Described below. Alias: projects ||
### Secure Logging Variables
@@ -51,6 +50,7 @@ This also speeds up the overall role.
|`controller_configuration_project_update_async_retries`|60|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|10|no|This sets the delay between retries for the role globally.|
|`controller_configuration_project_update_async_delay`|10|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/project_update/defaults/main.yml b/roles/project_update/defaults/main.yml
index 4aa399913..a909d681f 100644
--- a/roles/project_update/defaults/main.yml
+++ b/roles/project_update/defaults/main.yml
@@ -2,4 +2,5 @@
controller_configuration_project_update_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_project_update_async_retries: "{{ controller_configuration_async_retries | default(60) }}"
controller_configuration_project_update_async_delay: "{{ controller_configuration_async_delay | default(10) }}"
+controller_configuration_async_dir: null
...
diff --git a/roles/project_update/meta/argument_specs.yml b/roles/project_update/meta/argument_specs.yml
index cf2a6ad90..1c3ffa3c4 100644
--- a/roles/project_update/meta/argument_specs.yml
+++ b/roles/project_update/meta/argument_specs.yml
@@ -139,6 +139,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
controller_configuration_groups_secure_logging:
diff --git a/roles/project_update/tasks/main.yml b/roles/project_update/tasks/main.yml
index dad71857d..edbcb5f52 100644
--- a/roles/project_update/tasks/main.yml
+++ b/roles/project_update/tasks/main.yml
@@ -12,23 +12,30 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_projects }}"
+ loop: "{{ projects if projects is defined else controller_projects }}"
loop_control:
loop_var: "__project_update_update_item"
+ label: "{{ (__project_update_update_item.organization | default('')) }}/{{ __project_update_update_item.name }}"
no_log: "{{ controller_configuration_project_update_secure_logging }}"
when:
- controller_projects is defined
- - __project_update_update_item.update_project | default(false)
+ - __project_update_update_item.update_project | default(true)
- __project_update_update_item.state | default('present') != "absent"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __project_update_job_async
changed_when: not __project_update_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __project_update_job_async.failed is defined and __project_update_job_async.failed
- name: "Configure Controller Projects | Wait for finish the projects creation"
ansible.builtin.async_status:
@@ -40,8 +47,8 @@
loop: "{{ __project_update_job_async.results }}"
loop_control:
loop_var: __project_update_job_async_results_item
- when: __project_update_job_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __project_update_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_project_update_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/projects/README.md b/roles/projects/README.md
index 5a0a85e69..5655a98e3 100644
--- a/roles/projects/README.md
+++ b/roles/projects/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Projects on Ansible Controller.
+An Ansible Role to create/update/remove Projects on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|str|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|str|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|str|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|str|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_projects`|`see below`|yes|str|Data structure describing your project or projects Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_projects`|`see below`|yes|str|Data structure describing your project or projects Described below. Alias: projects ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_projects_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_projects_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_projects_async_retries`|`{{ controller_configuration_async_retries }}`|no|str|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|str|This sets the delay between retries for the role globally.|
|`controller_configuration_projects_async_delay`|`controller_configuration_async_delay`|no|str|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,6 +75,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`name`|""|yes|str|Name of Project|
+|`new_name`|""|no|Setting this option will change the existing name (looked up via the name field).|
|`copy_from`|""|no|str|Name or id to copy the project from. This will copy an existing project and change any parameters supplied.|
|`description`|`False`|no|str|Description of the Project.|
|`organization`|`False`|yes|str|Name of organization for project.|
diff --git a/roles/projects/defaults/main.yml b/roles/projects/defaults/main.yml
index c98b3a313..d60e66aee 100644
--- a/roles/projects/defaults/main.yml
+++ b/roles/projects/defaults/main.yml
@@ -4,4 +4,6 @@ controller_projects: []
controller_configuration_projects_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_projects_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_projects_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_projects_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/projects/meta/argument_specs.yml b/roles/projects/meta/argument_specs.yml
index 67ec7bec2..8951ac329 100644
--- a/roles/projects/meta/argument_specs.yml
+++ b/roles/projects/meta/argument_specs.yml
@@ -147,6 +147,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/projects/meta/main.yml b/roles/projects/meta/main.yml
index b94267153..8de201683 100644
--- a/roles/projects/meta/main.yml
+++ b/roles/projects/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/projects/tasks/main.yml b/roles/projects/tasks/main.yml
index 2bd2d727a..a0de767ee 100644
--- a/roles/projects/tasks/main.yml
+++ b/roles/projects/tasks/main.yml
@@ -1,53 +1,62 @@
---
-- name: Add Projects
+- name: "Managing Projects"
project:
name: "{{ __controller_project_item.name | mandatory }}"
+ new_name: "{{ __controller_project_item.new_name | default(omit, true) }}"
copy_from: "{{ __controller_project_item.copy_from | default(omit, true) }}"
- description: "{{ __controller_project_item.description | default(omit, true) }}"
+ description: "{{ __controller_project_item.description | default(('' if controller_configuration_projects_enforce_defaults else omit), true) }}"
scm_type: "{{ __controller_project_item.scm_type | default('manual') }}"
- scm_url: "{{ __controller_project_item.scm_url | default(omit, true) }}"
+ scm_url: "{{ __controller_project_item.scm_url | default(('' if controller_configuration_projects_enforce_defaults else omit), true) }}"
default_environment: "{{ __controller_project_item.default_environment | default(omit, true) }}"
- local_path: "{{ __controller_project_item.local_path | default(omit, true) }}"
- scm_branch: "{{ __controller_project_item.scm_branch | default(omit) }}"
- scm_refspec: "{{ __controller_project_item.scm_refspec | default(omit, true) }}"
+ local_path: "{{ __controller_project_item.local_path | default(('' if controller_configuration_projects_enforce_defaults else omit), true) }}"
+ scm_branch: "{{ __controller_project_item.scm_branch | default(('' if controller_configuration_projects_enforce_defaults else omit)) }}"
+ scm_refspec: "{{ __controller_project_item.scm_refspec | default(('' if controller_configuration_projects_enforce_defaults else omit), true) }}"
credential: "{{ __controller_project_item.credential.name | default(__controller_project_item.credential | default(__controller_project_item.scm_credential | default(omit, true))) }}"
signature_validation_credential: "{{ __controller_project_item.signature_validation_credential.name | default(__controller_project_item.signature_validation_credential | default(omit, true)) }}"
- scm_clean: "{{ __controller_project_item.scm_clean | default(omit) }}"
- scm_delete_on_update: "{{ __controller_project_item.scm_delete_on_update | default(omit) }}"
- scm_track_submodules: "{{ __controller_project_item.scm_track_submodules | default(omit) }}"
- scm_update_on_launch: "{{ __controller_project_item.scm_update_on_launch | default(omit) }}"
- scm_update_cache_timeout: "{{ __controller_project_item.scm_update_cache_timeout | default(omit, true) }}"
- allow_override: "{{ __controller_project_item.allow_override | default(omit) }}"
- timeout: "{{ __controller_project_item.job_timeout | default(__controller_project_item.timeout | default(omit, true)) }}"
- custom_virtualenv: "{{ __controller_project_item.custom_virtualenv | default(omit, true) }}"
- organization: "{{ __controller_project_item.organization.name | default(__controller_project_item.organization | default(omit)) }}"
+ scm_clean: "{{ __controller_project_item.scm_clean | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
+ scm_delete_on_update: "{{ __controller_project_item.scm_delete_on_update | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
+ scm_track_submodules: "{{ __controller_project_item.scm_track_submodules | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
+ scm_update_on_launch: "{{ __controller_project_item.scm_update_on_launch | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
+ scm_update_cache_timeout: "{{ __controller_project_item.scm_update_cache_timeout | default((0 if controller_configuration_projects_enforce_defaults else omit), true) }}"
+ allow_override: "{{ __controller_project_item.allow_override | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
+ timeout: "{{ __controller_project_item.job_timeout | default(__controller_project_item.timeout | default((0 if controller_configuration_projects_enforce_defaults else omit), true)) }}"
+ custom_virtualenv: "{{ __controller_project_item.custom_virtualenv | default(('' if controller_configuration_projects_enforce_defaults else omit), true) }}"
+ organization: "{{ __controller_project_item.organization.name | default(__controller_project_item.organization | default(('' if controller_configuration_projects_enforce_defaults else omit))) }}"
state: "{{ __controller_project_item.state | default(controller_state | default('present')) }}"
- wait: "{{ __controller_project_item.wait | default(omit) }}"
- update_project: "{{ __controller_project_item.update_project | default(omit) }}"
+ wait: "{{ __controller_project_item.wait | default((true if controller_configuration_projects_enforce_defaults else omit)) }}"
+ update_project: "{{ __controller_project_item.update_project | default((false if controller_configuration_projects_enforce_defaults else omit)) }}"
interval: "{{ __controller_project_item.interval | default(controller_configuration_projects_async_delay) }}"
- notification_templates_started: "{{ __controller_project_item.notification_templates_started | default(__controller_project_item.related.notification_templates_started | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_success: "{{ __controller_project_item.notification_templates_success | default(__controller_project_item.related.notification_templates_success | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_error: "{{ __controller_project_item.notification_templates_error | default(__controller_project_item.related.notification_templates_error | default([]) | map(attribute='name') | list) | default(omit, true) }}"
+ notification_templates_started: "{{ (__controller_project_item.related.notification_templates_started | map(attribute='name') | list if __controller_project_item.related.notification_templates_started is defined) | default(__controller_project_item.notification_templates_started) | default(([] if controller_configuration_projects_enforce_defaults else omit), true) }}"
+ notification_templates_success: "{{ (__controller_project_item.related.notification_templates_success | map(attribute='name') | list if __controller_project_item.related.notification_templates_success is defined) | default(__controller_project_item.notification_templates_success) | default(([] if controller_configuration_projects_enforce_defaults else omit), true) }}"
+ notification_templates_error: "{{ (__controller_project_item.related.notification_templates_error | map(attribute='name') | list if __controller_project_item.related.notification_templates_error is defined) | default(__controller_project_item.notification_templates_error) | default(([] if controller_configuration_projects_enforce_defaults else omit), true) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_projects }}"
+ loop: "{{ projects if projects is defined else controller_projects }}"
loop_control:
loop_var: __controller_project_item
+ label: "{{ __operation.verb }} Project {{ __controller_project_item.name }}"
no_log: "{{ controller_configuration_projects_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __projects_job_async
changed_when: not __projects_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_project_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Controller Projects | Wait for finish the projects creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __projects_job_async.failed is defined and __projects_job_async.failed
+
+- name: "Managing Projects | Wait for finish the projects management"
ansible.builtin.async_status:
jid: "{{ __projects_job_async_results_item.ansible_job_id }}"
register: __projects_job_async_result
@@ -57,8 +66,10 @@
loop: "{{ __projects_job_async.results }}"
loop_control:
loop_var: __projects_job_async_results_item
- when: __projects_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Project {{ __projects_job_async_results_item.__controller_project_item.name }} | Wait for finish the project {{ __operation.action }}"
+ when: not ansible_check_mode and __projects_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_projects_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__projects_job_async_results_item.__controller_project_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/roles/README.md b/roles/roles/README.md
index dbd660fcf..786daec6e 100644
--- a/roles/roles/README.md
+++ b/roles/roles/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create RBAC Entries on Ansible Controller.
+An Ansible Role to create/update/remove RBAC Entries on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,8 +22,25 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_roles`|`see below`|yes|Data structure describing your RBAC entries described below.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_role_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_role_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_role_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_role_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -59,7 +75,10 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`user`|""|no|str|The user for which the role applies|
+|`users`|""|no|list|The users for which the role applies|
|`team`|""|no|str|The team for which the role applies|
+|`teams`|""|no|list|The teams for which the role applies|
+|`roles`|""|no|str (see note below)|The roles which are applied to one of {`target_team`, `inventory`, `job_template`, `target_team`, `inventory`, `job_template`} for either `user` or `team` |
|`role`|""|no|str (see note below)|The role which is applied to one of {`target_team`, `inventory`, `job_template`, `target_team`, `inventory`, `job_template`} for either `user` or `team` |
|`target_team`|""|no|str|The team the role applies against|
|`target_teams`|""|no|list|The teams the role applies against|
@@ -76,11 +95,12 @@ This also speeds up the overall role.
|`lookup_organization`|""|no|str|Organization the inventories, job templates, projects, or workflows the items exists in. Used to help lookup the object, for organization roles see organization. If not provided, will lookup by name only, which does not work with duplicates.|
|`project`|""|no|str|The project the role applies against|
|`projects`|""|no|list|The project the role applies against|
+|`instance_groups`|""|no|list|The instance groups the role applies against|
|`state`|`present`|no|str|Desired state of the resource.|
#### Role
-`role` must be one of the following:
+`role` must be one of the following (or roles must contain a list made up from the following):
- `admin`
- `read`
@@ -97,6 +117,8 @@ This also speeds up the overall role.
- `notification_admin`
- `job_template_admin`
+Note that the `roles` option takes precedence over the `role` option and simply allows to specify multiple roles for a user or team (or set of users or teams).
+
### Standard RBAC Data Structure
#### Json Example
@@ -112,23 +134,31 @@ This also speeds up the overall role.
{
"team": "My Team",
"organization": "Default",
- "role": "execute"
+ "roles": [
+ "execute",
+ "read"
+ ]
}
]
}
```
-#### Yaml Example
+git check
```yaml
---
controller_roles:
- user: jdoe
+ users:
+ - thing1
+ - thing2
target_team: "My Team"
role: member
- team: "My Team"
organization: "Default"
- role: execute
+ roles:
+ - execute
+ - read
```
## Playbook Examples
diff --git a/roles/roles/defaults/main.yml b/roles/roles/defaults/main.yml
index 5e2d47836..769ef23d3 100644
--- a/roles/roles/defaults/main.yml
+++ b/roles/roles/defaults/main.yml
@@ -4,4 +4,6 @@ controller_roles: []
controller_configuration_role_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_role_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_role_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_role_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/roles/meta/argument_specs.yml b/roles/roles/meta/argument_specs.yml
index 62edc84c6..679842fa6 100644
--- a/roles/roles/meta/argument_specs.yml
+++ b/roles/roles/meta/argument_specs.yml
@@ -110,6 +110,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/roles/meta/main.yml b/roles/roles/meta/main.yml
index 9028cd25c..10e09fc7c 100644
--- a/roles/roles/meta/main.yml
+++ b/roles/roles/meta/main.yml
@@ -66,7 +66,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/roles/tasks/main.yml b/roles/roles/tasks/main.yml
index ab6018c9d..b60e3883c 100644
--- a/roles/roles/tasks/main.yml
+++ b/roles/roles/tasks/main.yml
@@ -1,45 +1,56 @@
---
-- name: Create Role Based Access Entry on Controller
+- name: "Managing Role Based Access Entries on Controller"
role:
- user: "{{ __controller_role_item.user | default(omit, true) }}"
- team: "{{ __controller_role_item.team | default(omit, true) }}"
- role: "{{ __controller_role_item.role | mandatory }}"
- target_team: "{{ __controller_role_item.target_team | default(omit, true) }}"
- target_teams: "{{ __controller_role_item.target_teams | default(omit, true) }}"
- inventory: "{{ __controller_role_item.inventory | default(omit, true) }}"
- inventories: "{{ __controller_role_item.inventories | default(omit, true) }}"
- job_template: "{{ __controller_role_item.job_template | default(omit, true) }}"
- job_templates: "{{ __controller_role_item.job_templates | default(omit, true) }}"
- workflow: "{{ __controller_role_item.workflow | default(omit, true) }}"
- workflows: "{{ __controller_role_item.workflows | default(omit, true) }}"
- credential: "{{ __controller_role_item.credential | default(omit, true) }}"
- credentials: "{{ __controller_role_item.credentials | default(omit, true) }}"
- organization: "{{ __controller_role_item.organization | default(omit, true) }}"
- organizations: "{{ __controller_role_item.organizations | default(omit, true) }}"
- lookup_organization: "{{ __controller_role_item.lookup_organization | default(omit, true) }}"
- project: "{{ __controller_role_item.project | default(omit, true) }}"
- projects: "{{ __controller_role_item.projects | default(omit, true) }}"
- state: "{{ __controller_role_item.state | default(controller_state | default('present')) }}"
+ user: "{{ __controller_role_item.0.user | default(__controller_role_item.user) | default(omit, true) }}"
+ users: "{{ __controller_role_item.0.users | default(__controller_role_item.users) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ team: "{{ __controller_role_item.0.team | default(__controller_role_item.team) | default(omit, true) }}"
+ teams: "{{ __controller_role_item.0.teams | default(__controller_role_item.teams) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ role: "{{ __controller_role_item.1 | default(__controller_role_item.role) | mandatory }}"
+ target_team: "{{ __controller_role_item.0.target_team | default(__controller_role_item.target_team) | default(omit, true) }}"
+ target_teams: "{{ __controller_role_item.0.target_teams | default(__controller_role_item.target_teams) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ inventory: "{{ __controller_role_item.0.inventory | default(__controller_role_item.inventory) | default(omit, true) }}"
+ inventories: "{{ __controller_role_item.0.inventories | default(__controller_role_item.inventories) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ job_template: "{{ __controller_role_item.0.job_template | default(__controller_role_item.job_template) | default(omit, true) }}"
+ job_templates: "{{ __controller_role_item.0.job_templates | default(__controller_role_item.job_templates) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ workflow: "{{ __controller_role_item.0.workflow | default(__controller_role_item.workflow) | default(omit, true) }}"
+ workflows: "{{ __controller_role_item.0.workflows | default(__controller_role_item.workflows) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ credential: "{{ __controller_role_item.0.credential | default(__controller_role_item.credential) | default(omit, true) }}"
+ credentials: "{{ __controller_role_item.0.credentials | default(__controller_role_item.credentials) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ organization: "{{ __controller_role_item.0.organization | default(__controller_role_item.organization) | default(omit, true) }}"
+ organizations: "{{ __controller_role_item.0.organizations | default(__controller_role_item.organizations) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ lookup_organization: "{{ __controller_role_item.0.lookup_organization | default(__controller_role_item.lookup_organization) | default(omit, true) }}"
+ project: "{{ __controller_role_item.0.project | default(__controller_role_item.project) | default(omit, true) }}"
+ projects: "{{ __controller_role_item.0.projects | default(__controller_role_item.projects) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ instance_groups: "{{ __controller_role_item.0.instance_groups | default(__controller_role_item.instance_groups) | default(([] if controller_configuration_role_enforce_defaults else omit), true) }}"
+ state: "{{ __controller_role_item.0.state | default(__controller_role_item.state) | default(controller_state | default('present')) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_roles }}"
+ loop: "{{ (controller_roles | subelements(['roles'], skip_missing=true)) + controller_roles | selectattr('roles', 'undefined') }}"
loop_control:
loop_var: __controller_role_item
+ label: "{{ __operation.verb }} Role Based Access Entry on Controller {{ __controller_role_item.1 | default(__controller_role_item.role) }}"
no_log: "{{ controller_configuration_role_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_role_job_async
changed_when: not __controller_role_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_role_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Roles | Wait for finish the Roles creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_role_job_async.failed is defined and __controller_role_job_async.failed
+
+- name: "Managing Roles | Wait for finish the Roles management"
ansible.builtin.async_status:
jid: "{{ __controller_role_job_async_results_item.ansible_job_id }}"
register: __controller_role_job_async_result
@@ -49,8 +60,10 @@
loop: "{{ __controller_role_job_async.results }}"
loop_control:
loop_var: __controller_role_job_async_results_item
- when: __controller_role_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Role {{ __controller_role_job_async_results_item.__controller_role_item.1 | default(__controller_role_job_async_results_item.__controller_role_item.role) }} | Wait for finish the Roles {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_role_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_role_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_role_job_async_results_item.__controller_role_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/roles/tests/configs/roles.yml b/roles/roles/tests/configs/roles.yml
index 7582ecd84..6c2659b32 100644
--- a/roles/roles/tests/configs/roles.yml
+++ b/roles/roles/tests/configs/roles.yml
@@ -2,7 +2,9 @@
controller_roles:
- user: admin
job_template: Demo Job Template
- role: read
+ roles:
+ - read
+ - execute
- inventory: Demo Inventory
user: admin
role: read
diff --git a/roles/schedules/README.md b/roles/schedules/README.md
index c1db6f125..9d5df9d64 100644
--- a/roles/schedules/README.md
+++ b/roles/schedules/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Schedules on Ansible Controller.
+An Ansible Role to create/update/remove Schedules on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_schedules`|`see below`|yes|Data structure describing your schedule or schedules Described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_schedules`|`see below`|yes|Data structure describing your schedule or schedules Described below. Alias: schedules ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_schedules_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_schedules_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_schedules_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_schedules_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/schedules/defaults/main.yml b/roles/schedules/defaults/main.yml
index 38555c283..0601fe5a0 100644
--- a/roles/schedules/defaults/main.yml
+++ b/roles/schedules/defaults/main.yml
@@ -4,4 +4,6 @@ controller_schedules: []
controller_configuration_schedules_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_schedules_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_schedules_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_schedules_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/schedules/meta/argument_specs.yml b/roles/schedules/meta/argument_specs.yml
index 39131cb00..4b7979cf4 100644
--- a/roles/schedules/meta/argument_specs.yml
+++ b/roles/schedules/meta/argument_specs.yml
@@ -132,6 +132,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/schedules/meta/main.yml b/roles/schedules/meta/main.yml
index 5f4cdc3cd..8950f55ec 100644
--- a/roles/schedules/meta/main.yml
+++ b/roles/schedules/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/schedules/tasks/main.yml b/roles/schedules/tasks/main.yml
index 4f9fd9192..d646e3fd2 100644
--- a/roles/schedules/tasks/main.yml
+++ b/roles/schedules/tasks/main.yml
@@ -1,50 +1,58 @@
---
-- name: Add Controller Schedule
+- name: "Managing Controller Schedules"
schedule:
name: "{{ __controller_schedule_item.name | mandatory }}"
new_name: "{{ __controller_schedule_item.new_name | default(omit, true) }}"
- description: "{{ __controller_schedule_item.description | default(omit, true) }}"
+ description: "{{ __controller_schedule_item.description | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
rrule: "{{ __controller_schedule_item.rrule | default(omit, true) }}"
- extra_data: "{{ __controller_schedule_item.extra_data | default(omit, true) }}"
- inventory: "{{ __controller_schedule_item.inventory | default(omit, true) }}"
+ extra_data: "{{ __controller_schedule_item.extra_data | default(({} if controller_configuration_schedules_enforce_defaults else omit), true) }}"
+ inventory: "{{ __controller_schedule_item.inventory | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
credentials: "{{ __controller_schedule_item.credentials | default(omit, true) }}"
- scm_branch: "{{ __controller_schedule_item.scm_branch | default(omit, true) }}"
- execution_environment: "{{ __controller_schedule_item.execution_environment.name | default(__controller_schedule_item.execution_environment | default(omit, true)) }}"
+ scm_branch: "{{ __controller_schedule_item.scm_branch | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
+ execution_environment: "{{ __controller_schedule_item.execution_environment.name | default(__controller_schedule_item.execution_environment | default(('' if controller_configuration_schedules_enforce_defaults else omit), true)) }}"
forks: "{{ __controller_schedule_item.forks | default(omit, true) }}"
instance_groups: "{{ __controller_schedule_item.instance_groups | default(omit, true) }}"
- job_slice_count: "{{ __controller_schedule_item.job_slice_count | default(omit, true) }}"
- labels: "{{ __controller_schedule_item.labels | default(__controller_schedule_item.related.labels | default([]) | map(attribute='name') | list if __controller_schedule_item.related.labels is defined else omit) }}"
+ job_slice_count: "{{ __controller_schedule_item.job_slice_count | default((1 if controller_configuration_schedules_enforce_defaults else omit), true) }}"
+ labels: "{{ (__controller_schedule_item.related.labels | map(attribute='name') | list if __controller_schedule_item.related.labels is defined) | default(__controller_schedule_item.labels) | default(([] if controller_configuration_schedules_enforce_defaults else omit), true) }}"
timeout: "{{ __controller_schedule_item.timeout | default(omit, true) }}"
job_type: "{{ __controller_schedule_item.job_type | default(omit, true) }}"
- job_tags: "{{ __controller_schedule_item.job_tags | default(omit, true) }}"
- skip_tags: "{{ __controller_schedule_item.skip_tags | default(omit, true) }}"
+ job_tags: "{{ __controller_schedule_item.job_tags | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
+ skip_tags: "{{ __controller_schedule_item.skip_tags | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
limit: "{{ __controller_schedule_item.limit | default(omit, true) }}"
- diff_mode: "{{ __controller_schedule_item.diff_mode | default(omit) }}"
+ diff_mode: "{{ __controller_schedule_item.diff_mode | default((false if controller_configuration_schedules_enforce_defaults else omit)) }}"
verbosity: "{{ __controller_schedule_item.verbosity | default(omit, true) }}"
- organization: "{{ __controller_schedule_item.organization | default(omit, true) }}"
+ organization: "{{ __controller_schedule_item.organization | default(('' if controller_configuration_schedules_enforce_defaults else omit), true) }}"
unified_job_template: "{{ __controller_schedule_item.unified_job_template | default(omit, true) }}"
- enabled: "{{ __controller_schedule_item.enabled | default(omit) }}"
+ enabled: "{{ __controller_schedule_item.enabled | default((true if controller_configuration_schedules_enforce_defaults else omit)) }}"
state: "{{ __controller_schedule_item.state | default(controller_state | default('present')) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_schedules }}"
+ loop: "{{ schedules if schedules is defined else controller_schedules }}"
loop_control:
loop_var: "__controller_schedule_item"
+ label: "{{ __operation.verb }} Controller Schedule {{ __controller_schedule_item.name }}"
no_log: "{{ controller_configuration_schedules_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_schedule_job_async
changed_when: not __controller_schedule_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_schedule_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Schedules | Wait for finish the Schedules creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_schedule_job_async.failed is defined and __controller_schedule_job_async.failed
+
+- name: "Managing Schedules | Wait for finish the Schedules management"
ansible.builtin.async_status:
jid: "{{ __controller_schedule_job_async_results_item.ansible_job_id }}"
register: __controller_schedule_job_async_result
@@ -54,8 +62,10 @@
loop: "{{ __controller_schedule_job_async.results }}"
loop_control:
loop_var: __controller_schedule_job_async_results_item
- when: __controller_schedule_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Schedule {{ __controller_schedule_job_async_results_item.__controller_schedule_item.name }} | Wait for finish the Schedules {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_schedule_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_schedules_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_schedule_job_async_results_item.__controller_schedule_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/settings/README.md b/roles/settings/README.md
index 4ee4dea42..52d4752a0 100644
--- a/roles/settings/README.md
+++ b/roles/settings/README.md
@@ -12,8 +12,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -22,6 +20,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_settings`|`see below`|yes|Data structure describing your settings described below.||
### Secure Logging Variables
@@ -49,6 +48,7 @@ This also speeds up the overall role.
|`controller_configuration_settings_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_settings_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
diff --git a/roles/settings/defaults/main.yml b/roles/settings/defaults/main.yml
index da7c0f903..2799dae7c 100644
--- a/roles/settings/defaults/main.yml
+++ b/roles/settings/defaults/main.yml
@@ -4,4 +4,5 @@ controller_settings: []
controller_configuration_settings_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_settings_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_settings_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
...
diff --git a/roles/settings/meta/argument_specs.yml b/roles/settings/meta/argument_specs.yml
index d0a7738af..968024db1 100644
--- a/roles/settings/meta/argument_specs.yml
+++ b/roles/settings/meta/argument_specs.yml
@@ -38,6 +38,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/settings/tasks/main.yml b/roles/settings/tasks/main.yml
index 71f5a2579..f693436bd 100644
--- a/roles/settings/tasks/main.yml
+++ b/roles/settings/tasks/main.yml
@@ -12,18 +12,25 @@
controller_password: "{{ controller_password | default(omit, true) }}"
controller_username: "{{ controller_username | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
# controller_settings must be either a dictionary/mapping or a list of dictionaries
loop: "{{ controller_settings is mapping | ternary([controller_settings], controller_settings) }}"
loop_control:
loop_var: __controller_setting_item
+ label: "{{ __controller_setting_item.name | default(__controller_setting_item.settings) }}"
no_log: "{{ controller_configuration_settings_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_setting_job_async
changed_when: not __controller_setting_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_setting_job_async.failed is defined and __controller_setting_job_async.failed
- name: "Configure Settings | Wait for finish the Settings creation"
ansible.builtin.async_status:
@@ -35,8 +42,8 @@
loop: "{{ __controller_setting_job_async.results }}"
loop_control:
loop_var: __controller_setting_job_async_results_item
- when: __controller_setting_job_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __controller_setting_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_settings_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/teams/README.md b/roles/teams/README.md
index 3b7805910..3b575426c 100644
--- a/roles/teams/README.md
+++ b/roles/teams/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Teams on Ansible Controller.
+An Ansible Role to create/update/remove Teams on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_teams`|`see below`|yes|Data structure describing your Teams described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_teams`|`see below`|yes|Data structure describing your Teams described below. Alias: teams ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_teams_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_teams_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_teams_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_teams_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
### Data structure `controller_teams:` should include following vars
diff --git a/roles/teams/defaults/main.yml b/roles/teams/defaults/main.yml
index bc96bd3c1..a93aabb48 100644
--- a/roles/teams/defaults/main.yml
+++ b/roles/teams/defaults/main.yml
@@ -4,4 +4,6 @@ controller_teams: []
controller_configuration_teams_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_teams_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_teams_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_teams_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/teams/meta/argument_specs.yml b/roles/teams/meta/argument_specs.yml
index 8758eb7ce..7bcf6818e 100644
--- a/roles/teams/meta/argument_specs.yml
+++ b/roles/teams/meta/argument_specs.yml
@@ -47,6 +47,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/teams/meta/main.yml b/roles/teams/meta/main.yml
index 5f9dc5b7e..dd09b4a32 100644
--- a/roles/teams/meta/main.yml
+++ b/roles/teams/meta/main.yml
@@ -68,7 +68,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/teams/tasks/main.yml b/roles/teams/tasks/main.yml
index 98cf6def0..ef917f07a 100644
--- a/roles/teams/tasks/main.yml
+++ b/roles/teams/tasks/main.yml
@@ -1,9 +1,9 @@
---
-- name: Create Ansible Controller Team
+- name: "Managing Ansible Controller Teams"
team:
name: "{{ __controller_team_item.name | mandatory }}"
new_name: "{{ __controller_team_item.new_name | default(omit, true) }}"
- description: "{{ __controller_team_item.description | default(omit, true) }}"
+ description: "{{ __controller_team_item.description | default(('' if controller_configuration_teams_enforce_defaults else omit), true) }}"
organization: "{{ __controller_team_item.organization.name | default(__controller_team_item.organization) | mandatory }}"
state: "{{ __controller_team_item.state | default(controller_state | default('present')) }}"
@@ -13,19 +13,27 @@
controller_password: "{{ controller_password | default(omit, true) }}"
controller_username: "{{ controller_username | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_teams }}"
+ loop: "{{ teams if teams is defined else controller_teams }}"
loop_control:
loop_var: __controller_team_item
+ label: "{{ __operation.verb }} Ansible Controller Team {{ __controller_team_item.name }}"
no_log: "{{ controller_configuration_teams_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_team_job_async
changed_when: not __controller_team_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_team_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Teams | Wait for finish the Teams creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_team_job_async.failed is defined and __controller_team_job_async.failed
+
+- name: "Managing Teams | Wait for finish the Teams management"
ansible.builtin.async_status:
jid: "{{ __controller_team_job_async_results_item.ansible_job_id }}"
register: __controller_team_job_async_result
@@ -35,8 +43,10 @@
loop: "{{ __controller_team_job_async.results }}"
loop_control:
loop_var: __controller_team_job_async_results_item
- when: __controller_team_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Teams | Wait for finish the Teams {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_team_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_teams_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_team_job_asycn_results_item.__controller_team_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/teams/tests/configs/teams.yml b/roles/teams/tests/configs/teams.yml
index fc48db5f2..d6886f235 100644
--- a/roles/teams/tests/configs/teams.yml
+++ b/roles/teams/tests/configs/teams.yml
@@ -1,12 +1,12 @@
---
controller_teams:
- name: "team1"
- desc: "My first team"
+ description: "My first team"
organization: "Default"
- name: "team2"
- desc: "My second team"
+ description: "My second team"
organization: "Default"
- name: "team3"
- desc: "My third team"
+ description: "My third team"
organization: "Default"
...
diff --git a/roles/users/README.md b/roles/users/README.md
index 579846700..5ef0258a4 100644
--- a/roles/users/README.md
+++ b/roles/users/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to add users to on Ansible Controller.
+An Ansible Role to add/update/remove users to on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,9 +22,26 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`controller_user_accounts`|`see below`|yes|Data structure describing your user entries described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_user_accounts`|`see below`|yes|Data structure describing your user entries described below. Alias: users ||
|`controller_user_default_password`|""|no|Global variable to set the password for all users.||
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_users_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_users_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
+
### Secure Logging Variables
The following Variables compliment each other.
@@ -52,6 +67,7 @@ This also speeds up the overall role.
|`controller_configuration_users_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_users_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -60,6 +76,7 @@ This also speeds up the overall role.
|Variable Name|Default Value|Required|Type|Description|
|:---:|:---:|:---:|:---:|:---:|
|`username`|""|yes|str|The username of the user|
+|`new_username`|""|yes|str|Setting this option will change the existing username (looked up via the username field).|
|`password`|"{{ controller_user_default_password }}"|no|str|The password of the user|
|`email`|""|yes|str|The email of the user|
|`first_name`|""|no|str|The first name of the user|
diff --git a/roles/users/defaults/main.yml b/roles/users/defaults/main.yml
index 012a65fdc..04f50dddd 100644
--- a/roles/users/defaults/main.yml
+++ b/roles/users/defaults/main.yml
@@ -8,4 +8,6 @@ controller_user_default_password: "change_me"
controller_configuration_users_secure_logging: "{{ controller_configuration_secure_logging | default('true') }}"
controller_configuration_users_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_users_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_users_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/users/meta/argument_specs.yml b/roles/users/meta/argument_specs.yml
index 8ca2d3cf5..c539646d8 100644
--- a/roles/users/meta/argument_specs.yml
+++ b/roles/users/meta/argument_specs.yml
@@ -76,6 +76,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/users/meta/main.yml b/roles/users/meta/main.yml
index 53efaeade..2217124a4 100644
--- a/roles/users/meta/main.yml
+++ b/roles/users/meta/main.yml
@@ -40,7 +40,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/users/tasks/main.yml b/roles/users/tasks/main.yml
index 835721785..360236e04 100644
--- a/roles/users/tasks/main.yml
+++ b/roles/users/tasks/main.yml
@@ -1,17 +1,18 @@
---
-# The user module is also an ansible.builtin module, but due to supporting both the awx.awx and automation.controller collections
+# The user module is also an ansible.builtin module, but due to supporting both the awx.awx and automation.Controller collections
# the FQCN cannot be used here.
-- name: Add controller user # noqa fqcn[action-core]
+- name: "Managing Controller Users" # noqa fqcn[action-core]
user:
username: "{{ __controller_user_accounts_item.user | default(__controller_user_accounts_item.username) | mandatory }}"
+ new_username: "{{ __controller_user_accounts_item.new_username | default(omit, true) }}"
# the 'true' in the second default leads to no password being set if the default password is empty
password: "{{ __controller_user_accounts_item.password | default(controller_user_default_password | default(omit, true)) }}"
email: "{{ __controller_user_accounts_item.email | default(omit, true) }}"
first_name: "{{ __controller_user_accounts_item.firstname | default(__controller_user_accounts_item.first_name | default(omit, true)) }}"
last_name: "{{ __controller_user_accounts_item.lastname | default(__controller_user_accounts_item.last_name | default(omit, true)) }}"
- is_superuser: "{{ __controller_user_accounts_item.is_superuser | default(__controller_user_accounts_item.superuser | default(omit)) }}"
- is_system_auditor: "{{ __controller_user_accounts_item.is_auditor | default(__controller_user_accounts_item.is_system_auditor | default(omit)) }}"
- update_secrets: "{{ __controller_user_accounts_item.update_secrets | default(omit) }}"
+ is_superuser: "{{ __controller_user_accounts_item.is_superuser | default(__controller_user_accounts_item.superuser | default((false if controller_configuration_users_enforce_defaults else omit))) }}"
+ is_system_auditor: "{{ __controller_user_accounts_item.is_auditor | default(__controller_user_accounts_item.is_system_auditor | default((false if controller_configuration_users_enforce_defaults else omit))) }}"
+ update_secrets: "{{ __controller_user_accounts_item.update_secrets | default((false if controller_configuration_users_enforce_defaults else omit)) }}"
organization: "{{ __controller_user_accounts_item.organization | default(omit) }}"
state: "{{ __controller_user_accounts_item.state | default(controller_state | default(omit, true)) }}"
@@ -20,20 +21,28 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
- loop: "{{ controller_user_accounts }}"
+ loop: "{{ users if users is defined else controller_user_accounts }}"
loop_control:
loop_var: __controller_user_accounts_item
+ label: "{{ __operation.verb }} Controller User {{ __controller_user_accounts_item.user | default(__controller_user_accounts_item.username) }}"
no_log: "{{ controller_configuration_users_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __controller_user_accounts_job_async
changed_when: not __controller_user_accounts_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_user_accounts_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Configure Users | Wait for finish the Users creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __controller_user_accounts_job_async.failed is defined and __controller_user_accounts_job_async.failed
+
+- name: "Managing Users | Wait for finish the Users management"
ansible.builtin.async_status:
jid: "{{ __controller_user_accounts_job_async_results_item.ansible_job_id }}"
register: __controller_user_accounts_job_async_result
@@ -43,8 +52,10 @@
loop: "{{ __controller_user_accounts_job_async.results }}"
loop_control:
loop_var: __controller_user_accounts_job_async_results_item
- when: __controller_user_accounts_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} User {{ __controller_user_accounts_job_async_results_item.__controller_user_accounts_item.user | default(__controller_user_accounts_job_async_results_item.__controller_user_accounts_item.username) }} | Wait for finish the Users {{ __operation.action }}"
+ when: not ansible_check_mode and __controller_user_accounts_job_async_results_item.ansible_job_id is defined
no_log: "{{ controller_configuration_users_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__controller_user_accounts_job_async_results_item.__controller_user_accounts_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/workflow_job_templates/README.md b/roles/workflow_job_templates/README.md
index 79d7db395..b557d592b 100644
--- a/roles/workflow_job_templates/README.md
+++ b/roles/workflow_job_templates/README.md
@@ -2,7 +2,7 @@
## Description
-An Ansible Role to create Workflow Job Templates on Ansible Controller.
+An Ansible Role to create/update/remove Workflow Job Templates on Ansible Controller.
## Requirements
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,7 +22,24 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
-|`workflow_job_templates`|`see below`|yes|Data structure describing your workflow job templates described below.||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
+|`controller_workflows`|`see below`|yes|Data structure describing your workflow job templates described below. Alias: workflow_job_templates ||
+
+### Enforcing defaults
+
+The following Variables compliment each other.
+If Both variables are not set, enforcing default values is not done.
+Enabling these variables enforce default values on options that are optional in the controller API.
+This should be enabled to enforce configuration and prevent configuration drift. It is recomended to be enabled, however it is not enforced by default.
+
+Enabling this will enforce configurtion without specifying every option in the configuration files.
+
+'controller_configuration_workflows_enforce_defaults' defaults to the value of 'controller_configuration_enforce_defaults' if it is not explicitly called. This allows for enforced defaults to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_workflows_enforce_defaults`|`False`|no|Whether or not to enforce default option values on only the applications role|
+|`controller_configuration_enforce_defaults`|`False`|no|This variable enables enforced default values as well, but is shared across multiple roles, see above.|
### Secure Logging Variables
@@ -51,6 +66,7 @@ This also speeds up the overall role.
|`controller_configuration_workflow_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
|`controller_configuration_workflow_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
## Data Structure
@@ -83,8 +99,8 @@ This also speeds up the overall role.
|`notification_templates_success`|""|no|list|The notifications on success to use for this organization in a list.|
|`scm_branch`|""|no|str|SCM branch applied as a prompt, assuming job template prompts for SCM branch|
|`state`|`present`|no|str|Desired state of the resource.|
-|`schema`|""|no|dict|A json list of nodes and their corresponding options. The sub-options are in the module doc.|
-|`destroy_current_schema`|""|no|dict|Set in order to destroy current schema on the workflow, used in cases where drastic changes to schema are happening.|
+|`workflow_nodes`|""|no|dict|A json list of nodes and their corresponding options. The sub-options are in the module doc.|
+|`destroy_current_nodes`|""|no|dict|Set in order to destroy current schema on the workflow, used in cases where drastic changes to schema are happening.|
|`survey_enabled`|""|no|bool|Enable a survey on the job template.|
|`survey_spec`|""|no|dict|JSON/YAML dict formatted survey definition.|
|`survey`|""|no|dict|JSON/YAML dict formatted survey definition. Alias of survey_spec|
diff --git a/roles/workflow_job_templates/defaults/main.yml b/roles/workflow_job_templates/defaults/main.yml
index e484716e7..127f51609 100644
--- a/roles/workflow_job_templates/defaults/main.yml
+++ b/roles/workflow_job_templates/defaults/main.yml
@@ -4,4 +4,6 @@ controller_workflows: []
workflow_job_templates_secure_logging: "{{ controller_configuration_secure_logging | default('false') }}"
controller_configuration_workflow_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
controller_configuration_workflow_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+controller_configuration_workflows_enforce_defaults: "{{ controller_configuration_enforce_defaults | default(false) }}"
...
diff --git a/roles/workflow_job_templates/meta/argument_specs.yml b/roles/workflow_job_templates/meta/argument_specs.yml
index f302d9ea6..b8cb25949 100644
--- a/roles/workflow_job_templates/meta/argument_specs.yml
+++ b/roles/workflow_job_templates/meta/argument_specs.yml
@@ -293,6 +293,10 @@ argument_specs:
default: 1
required: false
description: This variable sets delay between retries across all roles as a default.
+ controller_configuration_async_dir:
+ default: null
+ required: false
+ description: Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.
# No_log variables
diff --git a/roles/workflow_job_templates/meta/main.yml b/roles/workflow_job_templates/meta/main.yml
index 563c01781..7e1f66594 100644
--- a/roles/workflow_job_templates/meta/main.yml
+++ b/roles/workflow_job_templates/meta/main.yml
@@ -41,7 +41,8 @@ collections:
- ansible.controller
- awx.awx
-dependencies: []
-# List your role dependencies here, one per line. Be sure to remove the '[]' above,
-# if you add dependencies to this list.
+dependencies:
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
+ - role: global_vars
...
diff --git a/roles/workflow_job_templates/tasks/add_workflows_schema.yml b/roles/workflow_job_templates/tasks/add_workflows_schema.yml
index 86eb47cad..549b499ed 100644
--- a/roles/workflow_job_templates/tasks/add_workflows_schema.yml
+++ b/roles/workflow_job_templates/tasks/add_workflows_schema.yml
@@ -1,6 +1,6 @@
---
# Creating Workflow Node
-- name: Create the Workflow Node
+- name: Create the Workflow Nodes
workflow_job_template_node:
identifier: "{{ __workflow_loop_node_item.identifier | mandatory }}" # internal identification ID
extra_data: "{{ __workflow_loop_node_item.extra_data | default(omit, true) }}"
@@ -32,19 +32,26 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ __workflow_loop_item.simplified_workflow_nodes }}"
loop_control:
loop_var: __workflow_loop_node_item
+ label: "{{ __workflow_loop_item.name }}/{{ __workflow_loop_node_item.identifier }}"
no_log: "{{ workflow_job_templates_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __workflows_node_async
changed_when: not __workflows_node_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __workflows_node_async.failed is defined and __workflows_node_async.failed
- name: "Manage Workflows | Wait for finish the workflow creation"
ansible.builtin.async_status:
@@ -55,10 +62,10 @@
loop: "{{ __workflows_node_async.results }}"
loop_control:
loop_var: __workflows_node_async_results_item
- when: __workflows_node_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __workflows_node_async_results_item.ansible_job_id is defined
no_log: "{{ workflow_job_templates_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
# Create links between workflow node
- name: Create links between Workflow Nodes
@@ -73,22 +80,29 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ __workflow_loop_item.simplified_workflow_nodes }}"
loop_control:
loop_var: __workflow_loop_node_item
+ label: "{{ __workflow_loop_node_item.identifier }}"
no_log: "{{ workflow_job_templates_secure_logging }}"
# Execute only the nodes that define links to the following
when: ((__workflow_loop_node_item.always_nodes is defined and __workflow_loop_node_item.always_nodes | length > 0) or
(__workflow_loop_node_item.success_nodes is defined and __workflow_loop_node_item.success_nodes | length > 0) or
(__workflow_loop_node_item.failure_nodes is defined and __workflow_loop_node_item.failure_nodes | length > 0))
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __workflows_link_async
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __workflows_link_async.failed is defined and __workflows_link_async.failed
- name: "Manage Workflows | Wait for finish the workflow creation"
ansible.builtin.async_status:
@@ -100,8 +114,8 @@
loop: "{{ __workflows_link_async.results }}"
loop_control:
loop_var: __workflows_link_async_results_item
- when: __workflows_link_async_results_item.ansible_job_id is defined
+ when: not ansible_check_mode and __workflows_link_async_results_item.ansible_job_id is defined
no_log: "{{ workflow_job_templates_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
...
diff --git a/roles/workflow_job_templates/tasks/main.yml b/roles/workflow_job_templates/tasks/main.yml
index d2a05cd14..fa659c47c 100644
--- a/roles/workflow_job_templates/tasks/main.yml
+++ b/roles/workflow_job_templates/tasks/main.yml
@@ -1,58 +1,65 @@
---
-# Create Workflow
-- name: Manage Workflows
+- name: "Managing Workflows"
workflow_job_template:
name: "{{ __workflow_loop_item.name | mandatory }}"
new_name: "{{ __workflow_loop_item.new_name | default(omit, true) }}"
copy_from: "{{ __workflow_loop_item.copy_from | default(omit, true) }}"
- description: "{{ __workflow_loop_item.description | default(omit, true) }}"
- extra_vars: "{{ __workflow_loop_item.extra_vars | default(omit, true) }}"
- allow_simultaneous: "{{ __workflow_loop_item.allow_simultaneous | default(omit) }}"
- organization: "{{ __workflow_loop_item.organization.name | default(__workflow_loop_item.organization | default(omit, true)) }}"
- ask_variables_on_launch: "{{ __workflow_loop_item.ask_variables_on_launch | default(omit) }}" # only supported starting from Ansible 2.9
- inventory: "{{ __workflow_loop_item.inventory.name | default(__workflow_loop_item.inventory | default(omit, true)) }}"
- limit: "{{ __workflow_loop_item.limit | default(omit, true) }}"
- labels: "{{ __workflow_loop_item.labels | default(__workflow_loop_item.related.labels | default([]) | map(attribute='name') | list if __workflow_loop_item.related.labels is defined else omit) }}"
- scm_branch: "{{ __workflow_loop_item.scm_branch | default(omit, true) }}"
- ask_inventory_on_launch: "{{ __workflow_loop_item.ask_inventory_on_launch | default(omit) }}"
- ask_scm_branch_on_launch: "{{ __workflow_loop_item.ask_scm_branch_on_launch | default(omit) }}"
- ask_limit_on_launch: "{{ __workflow_loop_item.ask_limit_on_launch | default(omit) }}"
+ description: "{{ __workflow_loop_item.description | default(('' if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ extra_vars: "{{ __workflow_loop_item.extra_vars | default(({} if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ allow_simultaneous: "{{ __workflow_loop_item.allow_simultaneous | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ organization: "{{ __workflow_loop_item.organization.name | default(__workflow_loop_item.organization | default(('' if controller_configuration_workflows_enforce_defaults else omit), true)) }}"
+ ask_variables_on_launch: "{{ __workflow_loop_item.ask_variables_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ inventory: "{{ __workflow_loop_item.inventory.name | default(__workflow_loop_item.inventory | default(('' if controller_configuration_workflows_enforce_defaults else omit), true)) }}"
+ limit: "{{ __workflow_loop_item.limit | default((0 if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ labels: "{{ (__workflow_loop_item.related.labels | map(attribute='name') | list if __workflow_loop_item.related.labels is defined) | default(__workflow_loop_item.labels) | default(([] if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ scm_branch: "{{ __workflow_loop_item.scm_branch | default(('' if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ ask_inventory_on_launch: "{{ __workflow_loop_item.ask_inventory_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ ask_scm_branch_on_launch: "{{ __workflow_loop_item.ask_scm_branch_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ ask_limit_on_launch: "{{ __workflow_loop_item.ask_limit_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
webhook_service: "{{ __workflow_loop_item.webhook_service | default(omit, true) }}"
webhook_credential: "{{ __workflow_loop_item.webhook_credential.name | default(__workflow_loop_item.webhook_credential | default(omit, true)) }}"
- survey_enabled: "{{ __workflow_loop_item.survey_enabled | default(omit) }}"
- survey_spec: "{{ __workflow_loop_item.related.survey_spec | default(__workflow_loop_item.survey_spec | default(__workflow_loop_item.survey | default(omit, true))) }}"
- job_tags: "{{ __workflow_loop_item.job_tags | default(omit, true) }}"
- skip_tags: "{{ __workflow_loop_item.skip_tags | default(omit, true) }}"
- ask_tags_on_launch: "{{ __workflow_loop_item.ask_tags | default(__workflow_loop_item.ask_tags_on_launch | default(omit)) }}"
- ask_labels_on_launch: "{{ __workflow_loop_item.ask_labels_on_launch | default(omit) }}"
- ask_skip_tags_on_launch: "{{ __workflow_loop_item.ask_skip_tags | default(__workflow_loop_item.ask_skip_tags_on_launch | default(omit)) }}"
- schema: "{{ __workflow_loop_item.related.workflow_nodes | default(__workflow_loop_item.workflow_nodes | default(omit, true)) }}"
- destroy_current_schema: "{{ __workflow_loop_item.destroy_current_schema | default(omit) }}"
+ survey_enabled: "{{ __workflow_loop_item.survey_enabled | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ survey_spec: "{{ __workflow_loop_item.related.survey_spec | default(__workflow_loop_item.survey_spec | default(__workflow_loop_item.survey | default(({} if controller_configuration_workflows_enforce_defaults else omit), true))) }}"
+ job_tags: "{{ __workflow_loop_item.job_tags | default(('' if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ skip_tags: "{{ __workflow_loop_item.skip_tags | default(('' if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ ask_tags_on_launch: "{{ __workflow_loop_item.ask_tags | default(__workflow_loop_item.ask_tags_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit))) }}"
+ ask_labels_on_launch: "{{ __workflow_loop_item.ask_labels_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit)) }}"
+ ask_skip_tags_on_launch: "{{ __workflow_loop_item.ask_skip_tags | default(__workflow_loop_item.ask_skip_tags_on_launch | default((false if controller_configuration_workflows_enforce_defaults else omit))) }}"
+ workflow_nodes: "{{ __workflow_loop_item.related.workflow_nodes | default(__workflow_loop_item.workflow_nodes | default(([] if controller_configuration_workflows_enforce_defaults else omit), true)) }}"
+ destroy_current_nodes: "{{ __workflow_loop_item.destroy_current_nodes | default(__workflow_loop_item.destroy_current_schema | default((false if controller_configuration_workflows_enforce_defaults else omit))) }}"
state: "{{ __workflow_loop_item.state | default(controller_state | default('present')) }}"
- notification_templates_started: "{{ __workflow_loop_item.notification_templates_started | default(__workflow_loop_item.related.notification_templates_started | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_success: "{{ __workflow_loop_item.notification_templates_success | default(__workflow_loop_item.related.notification_templates_success | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_error: "{{ __workflow_loop_item.notification_templates_error | default(__workflow_loop_item.related.notification_templates_error | default([]) | map(attribute='name') | list) | default(omit, true) }}"
- notification_templates_approvals: "{{ __workflow_loop_item.notification_templates_approvals | default(__workflow_loop_item.related.notification_templates_approvals | default([]) | map(attribute='name') | list) | default(omit, true) }}"
+ notification_templates_started: "{{ (__workflow_loop_item.related.notification_templates_started | map(attribute='name') | list if __workflow_loop_item.related.notification_templates_started is defined) | default(__workflow_loop_item.notification_templates_started) | default(([] if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ notification_templates_success: "{{ (__workflow_loop_item.related.notification_templates_success | map(attribute='name') | list if __workflow_loop_item.related.notification_templates_success is defined) | default(__workflow_loop_item.notification_templates_success) | default(([] if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ notification_templates_error: "{{ (__workflow_loop_item.related.notification_templates_error | map(attribute='name') | list if __workflow_loop_item.related.notification_templates_error is defined) | default(__workflow_loop_item.notification_templates_error) | default(([] if controller_configuration_workflows_enforce_defaults else omit), true) }}"
+ notification_templates_approvals: "{{ (__workflow_loop_item.related.notification_templates_approvals | map(attribute='name') | list if __workflow_loop_item.related.notification_templates_approvals is defined) | default(__workflow_loop_item.notification_templates_approvals) | default(([] if controller_configuration_workflows_enforce_defaults else omit), true) }}"
# Role Standard Options
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
- loop: "{{ controller_workflows }}"
+ loop: "{{ workflow_job_templates if workflow_job_templates is defined else controller_workflows }}"
loop_control:
loop_var: __workflow_loop_item
+ label: "{{ __operation.verb }} Workflow {{ __workflow_loop_item.name }}"
no_log: "{{ workflow_job_templates_secure_logging }}"
- async: 1000
+ async: "{{ ansible_check_mode | ternary(0, 1000) }}"
poll: 0
register: __workflows_job_async
changed_when: not __workflows_job_async.changed
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__workflow_loop_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
-- name: "Manage Workflows | Wait for finish the workflow creation"
+- name: "Flag for errors (check mode only)"
+ ansible.builtin.set_fact:
+ error_flag: true
+ when: ansible_check_mode and __workflows_job_async.failed is defined and __workflows_job_async.failed
+
+- name: "Managing Workflows | Wait for finish the workflow management"
ansible.builtin.async_status:
jid: "{{ __workflows_job_async_results_item.ansible_job_id }}"
register: __workflows_job_async_result
@@ -62,15 +69,17 @@
loop: "{{ __workflows_job_async.results }}"
loop_control:
loop_var: __workflows_job_async_results_item
- when: __workflows_job_async_results_item.ansible_job_id is defined
+ label: "{{ __operation.verb }} Workflow {{ __workflows_job_async_results_item.__workflow_loop_item.name }} | Wait for finish the workflow {{ __operation.action }}"
+ when: not ansible_check_mode and __workflows_job_async_results_item.ansible_job_id is defined
no_log: "{{ workflow_job_templates_secure_logging }}"
vars:
- ansible_async_dir: '/tmp/.ansible_async'
+ __operation: "{{ operation_translate[__workflows_job_async_results_item.__workflow_loop_item.state | default(controller_state) | default('present')] }}"
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
# Create links between workflow node
- name: Loop over nodes in schema to add to workflow templates
ansible.builtin.include_tasks: "add_workflows_schema.yml"
- loop: "{{ controller_workflows }}"
+ loop: "{{ controller_workflows | default(workflow_job_templates) }}"
loop_control:
loop_var: __workflow_loop_item
when:
diff --git a/roles/workflow_job_templates/tests/configs/controller_workflows.yml b/roles/workflow_job_templates/tests/configs/controller_workflows.yml
index 11c9aa506..c78e1a59e 100644
--- a/roles/workflow_job_templates/tests/configs/controller_workflows.yml
+++ b/roles/workflow_job_templates/tests/configs/controller_workflows.yml
@@ -21,7 +21,6 @@ controller_workflows:
schedules: []
workflow_nodes:
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
@@ -77,7 +76,6 @@ controller_workflows:
identifier: d9779889-cfdb-4a8c-8a11-1f54acf84aca
type: workflow_job_template_node
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
@@ -134,7 +132,6 @@ controller_workflows:
option_true_false: 'yes'
target_groups:
- group1
- inventory:
scm_branch:
job_type:
job_tags:
@@ -171,7 +168,6 @@ controller_workflows:
identifier: 28910097-e606-4252-8aa9-2c1a0b8b6c92
type: workflow_job_template_node
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
@@ -208,7 +204,6 @@ controller_workflows:
identifier: ca7ffc3b-8401-4153-83bf-bb3dd918ca87
type: workflow_job_template_node
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
@@ -322,7 +317,6 @@ controller_workflows:
schedules: []
workflow_nodes:
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
@@ -370,7 +364,6 @@ controller_workflows:
identifier: d9779889-cfdb-4a8c-8a11-1f54acf84aca
type: workflow_job_template_node
- extra_data: {}
- inventory:
scm_branch:
job_type:
job_tags:
diff --git a/roles/workflow_launch/README.md b/roles/workflow_launch/README.md
index ca85e5ebe..53478aef4 100644
--- a/roles/workflow_launch/README.md
+++ b/roles/workflow_launch/README.md
@@ -14,8 +14,6 @@ Currently:
## Variables
-### Authentication
-
|Variable Name|Default Value|Required|Description|Example|
|:---|:---:|:---:|:---|:---|
|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
@@ -24,6 +22,7 @@ Currently:
|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_request_timeout`|`10`|no|Specify the timeout in seconds Ansible should use in requests to the controller host.||
|`controller_workflow_launch_jobs`|`see below`|yes|Data structure describing workflow or workflows to launch Described below.||
### Secure Logging Variables
diff --git a/roles/workflow_launch/tasks/main.yml b/roles/workflow_launch/tasks/main.yml
index 8fe9930a7..d48e74e7c 100644
--- a/roles/workflow_launch/tasks/main.yml
+++ b/roles/workflow_launch/tasks/main.yml
@@ -2,7 +2,7 @@
# Launch Controller Workflow
- name: Launch a Controller Workflow
workflow_launch:
- name: "{{ __workflow_launch_item.name }}"
+ name: "{{ __workflow_launch_item.name | mandatory }}"
organization: "{{ __workflow_launch_item.organization | default(omit, true) }}"
inventory: "{{ __workflow_launch_item.inventory | default(omit, true) }}"
limit: "{{ __workflow_launch_item.limit | default(omit, true) }}"
@@ -16,12 +16,14 @@
controller_username: "{{ controller_username | default(omit, true) }}"
controller_password: "{{ controller_password | default(omit, true) }}"
controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ request_timeout: "{{ controller_request_timeout | default(omit, true) }}"
controller_host: "{{ controller_hostname | default(omit, true) }}"
controller_config_file: "{{ controller_config_file | default(omit, true) }}"
validate_certs: "{{ controller_validate_certs | default(omit) }}"
loop: "{{ controller_workflow_launch_jobs }}"
loop_control:
loop_var: "__workflow_launch_item"
+ label: "{{ (__workflow_launch_item.organization | default('')) }}/{{ __workflow_launch_item.name }}"
no_log: "{{ controller_configuration_workflow_launch_secure_logging }}"
register: launched_controller_workflows
when: controller_workflow_launch_jobs is defined
diff --git a/tests/config.yml b/tests/config.yml
new file mode 100644
index 000000000..a1993a256
--- /dev/null
+++ b/tests/config.yml
@@ -0,0 +1,6 @@
+---
+# See template for more information:
+# https://github.com/ansible/ansible/blob/devel/test/lib/ansible_test/config/config.yml
+modules:
+ python_requires: controller
+...
diff --git a/tests/configs/bulk_hosts.yml b/tests/configs/bulk_hosts.yml
new file mode 100644
index 000000000..e3fea748a
--- /dev/null
+++ b/tests/configs/bulk_hosts.yml
@@ -0,0 +1,10 @@
+---
+temp_controller_bulk_hosts:
+ - inventory: localhost
+ hosts:
+ - name: 10.0.0.1
+ - name: 10.0.0.2
+ variables:
+ some_var: some_val
+ ansible_connection: local
+...
diff --git a/tests/configs/bulk_jobs.yml b/tests/configs/bulk_jobs.yml
new file mode 100644
index 000000000..3555f570c
--- /dev/null
+++ b/tests/configs/bulk_jobs.yml
@@ -0,0 +1,8 @@
+---
+temp_controller_bulk_launch_jobs:
+ - name: My Bulk Job Launch
+ jobs:
+ - unified_job_template: 7
+ - unified_job_template: 15
+ organization: Default
+...
diff --git a/tests/configs/controller_auth.yml b/tests/configs/controller_auth.yml
index 354e3050b..3df52670f 100644
--- a/tests/configs/controller_auth.yml
+++ b/tests/configs/controller_auth.yml
@@ -4,4 +4,5 @@
controller_username: admin
controller_password: password
controller_validate_certs: false
+controller_configuration_enforce_defaults: true
...
diff --git a/tests/configs/differential_items.yml b/tests/configs/differential_items.yml
index 3adeff41c..14bc82ac4 100644
--- a/tests/configs/differential_items.yml
+++ b/tests/configs/differential_items.yml
@@ -45,17 +45,20 @@ differential_items:
organization: Default
scm_type: git
scm_url: https://github.com/ansible/tower-example.git
+ state: present
- description: ansible-examples
name: Test Inventory source project
organization: Default
scm_type: git
scm_url: https://github.com/ansible/ansible-examples.git
+ state: present
- credential: gitlab-personal-access-token for satqe_auto_droid
description: ansible-examples
name: Test Inventory source project with credential
organization: Default
scm_type: git
scm_url: https://github.com/ansible/ansible-examples.git
+ state: present
wait: false
- description: Test Project 1
name: Test Project
@@ -64,6 +67,7 @@ differential_items:
scm_clean: true
scm_type: git
scm_url: https://github.com/ansible/tower-example.git
+ state: present
- name: Demo Project
organization: Default
state: absent
@@ -73,6 +77,9 @@ differential_items:
- name: "cyberark"
credential_type: CyberArk Central Credential Provider Lookup
organization: Default
+ - name: Demo Credential
+ organization: Default
+ credential_type: "Machine"
expected_test_result:
- name: gitlab
organization: Default
@@ -99,6 +106,9 @@ differential_items:
- name: satlab-admin-inventory
organization: Default
state: absent
+ - name: test_constructed
+ organization: Default
+ state: absent
- name: Test Inventory - Smart
organization: Default
state: absent
diff --git a/tests/configs/inventories.yml b/tests/configs/inventories.yml
index e520b0c73..896103673 100644
--- a/tests/configs/inventories.yml
+++ b/tests/configs/inventories.yml
@@ -22,4 +22,9 @@ controller_inventories:
description: created by Ansible Playbook
kind: smart
host_filter: "name__icontains=localhost"
+ - name: test_constructed
+ organization: Default
+ kind: constructed
+ input_inventories:
+ - localhost
...
diff --git a/tests/configs/inventory_sources.yml b/tests/configs/inventory_sources.yml
index 42a684172..cf0dbf448 100644
--- a/tests/configs/inventory_sources.yml
+++ b/tests/configs/inventory_sources.yml
@@ -40,5 +40,7 @@ controller_inventory_sources:
organization: Satellite
source: scm
state: absent
- # more options can be provided but for scm source we are using, we need only this much.
+ - name: "Auto-created source for: test_constructed"
+ inventory: test_constructed
+ source: constructed
...
diff --git a/tests/configs/roles.yml b/tests/configs/roles.yml
index 24fd1d1df..48dd4d14b 100644
--- a/tests/configs/roles.yml
+++ b/tests/configs/roles.yml
@@ -8,7 +8,9 @@ controller_roles:
role: use
- inventory: RHVM-02
team: satlab-admin
- role: admin
+ roles:
+ - admin
+ - use
# - workflow: Test workflow 1
# team: satellite-qe
# role: execute
diff --git a/tests/configs/schedule.yml b/tests/configs/schedule.yml
index e2ab685af..c587ec84d 100644
--- a/tests/configs/schedule.yml
+++ b/tests/configs/schedule.yml
@@ -10,6 +10,7 @@ controller_schedules:
rrule: "DTSTART:20200101T000000Z RRULE:FREQ=HOURLY;INTERVAL=3"
execution_environment: My EE
forks: 2
+ limit: all
instance_groups:
- test_instance_group
labels:
diff --git a/tests/configs/templates.yml b/tests/configs/templates.yml
index df1889a05..20a36a495 100644
--- a/tests/configs/templates.yml
+++ b/tests/configs/templates.yml
@@ -40,6 +40,7 @@ controller_templates:
ask_job_slice_count_on_launch: true
ask_labels_on_launch: true
ask_timeout_on_launch: true
+ ask_limit_on_launch: true
prevent_instance_group_fallback: true
survey_spec:
name: ''
diff --git a/tests/configs_export_model/credential_types_export.yml b/tests/configs_export_model/credential_types_export.yml
index 1d0251009..84a8aa991 100644
--- a/tests/configs_export_model/credential_types_export.yml
+++ b/tests/configs_export_model/credential_types_export.yml
@@ -1,5 +1,5 @@
---
-controller_credential_types:
+credential_types:
- name: REST API Credential
description: REST API Credential
kind: cloud
diff --git a/tests/configs_export_model/credentials_export.yml b/tests/configs_export_model/credentials_export.yml
index 0f3e4072b..e62e5ea0a 100644
--- a/tests/configs_export_model/credentials_export.yml
+++ b/tests/configs_export_model/credentials_export.yml
@@ -1,5 +1,5 @@
---
-controller_credentials:
+credentials:
- name: AWX-Collection-tests-controller_workflow_job_template-scm-cred
description: ''
inputs: {}
@@ -62,4 +62,97 @@ controller_credentials:
organization:
name: Default
type: organization
+ - name: admin@internal-RHVM-01
+ credential_type:
+ kind: cloud
+ name: Red Hat Virtualization
+ type: credential_type
+ description: infra-rhvm-01 creds for inventory sources.
+ inputs:
+ host: https://example.com/ovirt-engine/api
+ password: ""
+ username: user
+ natural_key:
+ credential_type:
+ kind: cloud
+ name: Red Hat Virtualization
+ type: credential_type
+ name: admin@internal-RHVM-01
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ organization:
+ name: Satellite
+ type: organization
+ - name: cyberark
+ credential_type:
+ kind: external
+ name: CyberArk Central Credential Provider Lookup
+ type: credential_type
+ description: CyberArk Lookup Credential
+ inputs:
+ app_id: ""
+ url: https://cyberark.example.com
+ natural_key:
+ credential_type:
+ kind: external
+ name: CyberArk Central Credential Provider Lookup
+ type: credential_type
+ name: cyberark
+ organization:
+ name: Default
+ type: organization
+ type: credential
+ organization:
+ name: Default
+ type: organization
+ - name: gitlab-personal-access-token for satqe_auto_droid
+ credential_type:
+ kind: scm
+ name: Source Control
+ type: credential_type
+ description:
+ General purpose token that can be used by anyone for satlab-admin(or
+ other private) repo clone
+ inputs:
+ password: ""
+ username: gitlab
+ natural_key:
+ credential_type:
+ kind: scm
+ name: Source Control
+ type: credential_type
+ name: gitlab-personal-access-token for satqe_auto_droid
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ organization:
+ name: Satellite
+ type: organization
+ - name: machine-creds-with-jenkins-pvt-key
+ credential_type:
+ kind: ssh
+ name: Machine
+ type: credential_type
+ description:
+ This credential can be used with any vm that contains jenkins_public
+ key in authorized keys
+ inputs:
+ ssh_key_data: ""
+ username: root
+ natural_key:
+ credential_type:
+ kind: ssh
+ name: Machine
+ type: credential_type
+ name: machine-creds-with-jenkins-pvt-key
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ organization:
+ name: Satellite
+ type: organization
...
diff --git a/tests/configs_export_model/differential_items.yml b/tests/configs_export_model/differential_items.yml
new file mode 100644
index 000000000..ec9b97fe9
--- /dev/null
+++ b/tests/configs_export_model/differential_items.yml
@@ -0,0 +1,472 @@
+---
+differential_expected:
+ credential_types: []
+ credentials:
+ - credential_type:
+ kind: vault
+ name: Vault
+ type: credential_type
+ description: satlab-admin-vault ******** aka vault_secret
+ inputs:
+ vault_password: ""
+ name: satlab-admin-vault
+ natural_key:
+ credential_type:
+ kind: vault
+ name: Vault
+ type: credential_type
+ name: satlab-admin-vault
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ organization:
+ name: Satellite
+ type: organization
+ state: absent
+ inventory:
+ - description: created by Ansible Playbook - for RHVM-02
+ host_filter:
+ kind: ""
+ name: RHVM-02
+ natural_key:
+ name: RHVM-02
+ organization:
+ name: Satellite
+ type: organization
+ type: inventory
+ organization:
+ name: Satellite
+ type: organization
+ prevent_instance_group_fallback: true
+ related:
+ groups: []
+ hosts: []
+ labels: []
+ state: absent
+ variables: "{}"
+ inventory_sources:
+ - credential:
+ credential_type:
+ kind: cloud
+ name: Red Hat Virtualization
+ type: credential_type
+ name: admin@internal-RHVM-01
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ description: ""
+ enabled_value: ""
+ enabled_var: ""
+ execution_environment:
+ host_filter: ""
+ inventory:
+ name: RHVM-01
+ organization:
+ name: Satellite
+ type: organization
+ type: inventory
+ limit: ""
+ name: RHVM-01
+ natural_key:
+ inventory:
+ name: RHVM-01
+ organization:
+ name: Satellite
+ type: organization
+ type: inventory
+ name: RHVM-01
+ type: inventory_source
+ overwrite: true
+ overwrite_vars: false
+ related:
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ schedules: []
+ scm_branch: ""
+ source: scm
+ source_path: phillips_hue/hosts
+ source_project:
+ name: Test Inventory source project
+ organization:
+ name: Satellite
+ type: organization
+ type: project
+ source_vars: ""
+ state: absent
+ timeout: 0
+ update_cache_timeout: 0
+ update_on_launch: true
+ verbosity: 1
+ job_templates:
+ - allow_simultaneous: false
+ ask_credential_on_launch: false
+ ask_diff_mode_on_launch: false
+ ask_execution_environment_on_launch: true
+ ask_forks_on_launch: true
+ ask_instance_groups_on_launch: true
+ ask_inventory_on_launch: true
+ ask_job_slice_count_on_launch: true
+ ask_job_type_on_launch: false
+ ask_labels_on_launch: true
+ ask_limit_on_launch: true
+ ask_scm_branch_on_launch: false
+ ask_skip_tags_on_launch: false
+ ask_tags_on_launch: false
+ ask_timeout_on_launch: true
+ ask_variables_on_launch: false
+ ask_verbosity_on_launch: false
+ become_enabled: false
+ description: ""
+ diff_mode: false
+ execution_environment:
+ name: My EE
+ type: execution_environment
+ extra_vars: "{}"
+ force_handlers: false
+ forks: 0
+ host_config_key: ""
+ inventory:
+ name: localhost
+ organization:
+ name: Satellite
+ type: organization
+ type: inventory
+ job_slice_count: 1
+ job_tags: ""
+ job_type: run
+ limit: ""
+ name: Demo Job Template
+ natural_key:
+ name: Demo Job Template
+ organization:
+ name: Default
+ type: organization
+ type: job_template
+ playbook: helloworld.yml
+ prevent_instance_group_fallback: true
+ project:
+ name: Test Project
+ organization:
+ name: Default
+ type: organization
+ type: project
+ related:
+ credentials:
+ - credential_type:
+ kind: ssh
+ name: Machine
+ type: credential_type
+ name: Demo Credential
+ organization:
+ type: credential
+ labels: []
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ schedules:
+ - description: Another demonstration
+ diff_mode: false
+ enabled: true
+ execution_environment:
+ name: My EE
+ type: execution_environment
+ extra_data: {}
+ forks: 2
+ inventory:
+ name: localhost
+ organization:
+ name: Satellite
+ type: organization
+ type: inventory
+ job_slice_count: 1
+ job_tags: ""
+ job_type:
+ limit: all
+ name: Demo Schedule 2
+ natural_key:
+ name: Demo Schedule 2
+ type: schedule
+ unified_job_template:
+ name: Demo Job Template
+ organization:
+ name: Default
+ type: organization
+ type: job_template
+ related:
+ credentials: []
+ rrule: DTSTART:20200101T000000Z RRULE:FREQ=HOURLY;INTERVAL=3
+ scm_branch: ""
+ skip_tags: ""
+ timeout: 165
+ unified_job_template:
+ name: Demo Job Template
+ organization:
+ name: Default
+ type: organization
+ type: job_template
+ verbosity:
+ survey_spec:
+ description: ""
+ name: ""
+ spec:
+ - choices: ""
+ default: infra-ansible-tower-testing.infra.sat.rdu2.redhat.com
+ max: 1024
+ min: 0
+ new_question: true
+ question_description:
+ target host is required for playbook to work, this
+ host needs to exist in the inventory
+ question_name: Target Host
+ required: true
+ type: text
+ variable: target_hosts
+ scm_branch: ""
+ skip_tags: ""
+ start_at_task: ""
+ state: absent
+ survey_enabled: false
+ timeout: 0
+ use_fact_cache: false
+ verbosity: 0
+ webhook_credential:
+ webhook_service: ""
+ notification_templates:
+ - description: Send out emails for tower jobs
+ messages: {}
+ name: Email notification
+ natural_key:
+ name: Email notification
+ organization:
+ name: Default
+ type: organization
+ type: notification_template
+ notification_configuration:
+ host: smtp.example.com
+ password: ""
+ port: 25
+ recipients:
+ - admin@example.com
+ sender: tower0@example.com
+ timeout: 30
+ use_ssl: false
+ use_tls: false
+ username: ""
+ notification_type: email
+ organization:
+ name: Default
+ type: organization
+ state: absent
+ organizations: []
+ projects:
+ - allow_override: false
+ credential:
+ default_environment:
+ description: ansible-examples
+ local_path: _10__test_inventory_source_project
+ name: Test Inventory source project
+ natural_key:
+ name: Test Inventory source project
+ organization:
+ name: Satellite
+ type: organization
+ type: project
+ organization:
+ name: Satellite
+ type: organization
+ related:
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ scm_branch: ""
+ scm_clean: false
+ scm_delete_on_update: false
+ scm_refspec: ""
+ scm_track_submodules: false
+ scm_type: git
+ scm_update_cache_timeout: 0
+ scm_update_on_launch: false
+ scm_url: https://github.com/ansible/ansible-examples.git
+ signature_validation_credential:
+ state: absent
+ timeout: 0
+ - allow_override: false
+ credential:
+ credential_type:
+ kind: scm
+ name: Source Control
+ type: credential_type
+ name: gitlab-personal-access-token for satqe_auto_droid
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ default_environment:
+ description: ansible-examples
+ local_path: _11__test_inventory_source_project_with_credential
+ name: Test Inventory source project with credential
+ natural_key:
+ name: Test Inventory source project with credential
+ organization:
+ name: Satellite
+ type: organization
+ type: project
+ organization:
+ name: Satellite
+ type: organization
+ related:
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ scm_branch: ""
+ scm_clean: false
+ scm_delete_on_update: false
+ scm_refspec: ""
+ scm_track_submodules: false
+ scm_type: git
+ scm_update_cache_timeout: 0
+ scm_update_on_launch: false
+ scm_url: https://github.com/ansible/ansible-examples.git
+ signature_validation_credential:
+ state: absent
+ timeout: 0
+ - allow_override: false
+ credential:
+ default_environment:
+ description: ansible-examples
+ local_path: _20__test_inventory_source_project
+ name: Test Inventory source project
+ natural_key:
+ name: Test Inventory source project
+ organization:
+ name: Default
+ type: organization
+ type: project
+ organization:
+ name: Default
+ type: organization
+ related:
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ scm_branch: ""
+ scm_clean: false
+ scm_delete_on_update: false
+ scm_refspec: ""
+ scm_track_submodules: false
+ scm_type: git
+ scm_update_cache_timeout: 0
+ scm_update_on_launch: false
+ scm_url: https://github.com/ansible/ansible-examples.git
+ signature_validation_credential:
+ state: absent
+ timeout: 0
+ - allow_override: false
+ credential:
+ credential_type:
+ kind: scm
+ name: Source Control
+ type: credential_type
+ name: gitlab-personal-access-token for satqe_auto_droid
+ organization:
+ name: Satellite
+ type: organization
+ type: credential
+ default_environment:
+ description: ansible-examples
+ local_path: _21__test_inventory_source_project_with_credential
+ name: Test Inventory source project with credential
+ natural_key:
+ name: Test Inventory source project with credential
+ organization:
+ name: Default
+ type: organization
+ type: project
+ organization:
+ name: Default
+ type: organization
+ related:
+ notification_templates_error: []
+ notification_templates_started: []
+ notification_templates_success: []
+ scm_branch: ""
+ scm_clean: false
+ scm_delete_on_update: false
+ scm_refspec: ""
+ scm_track_submodules: false
+ scm_type: git
+ scm_update_cache_timeout: 0
+ scm_update_on_launch: false
+ scm_url: https://github.com/ansible/ansible-examples.git
+ signature_validation_credential:
+ state: absent
+ timeout: 0
+ teams:
+ - description: ""
+ name: differential-1
+ natural_key:
+ name: differential-1
+ organization:
+ name: Default
+ type: organization
+ type: team
+ organization:
+ name: Default
+ type: organization
+ related:
+ roles: []
+ state: absent
+ users:
+ - email: admin@localhost
+ state: absent
+ username: admin
+ first_name: ""
+ is_superuser: true
+ is_system_auditor: false
+ last_name: ""
+ natural_key:
+ type: user
+ username: admin
+ password: ''
+ related:
+ roles:
+ - content_object:
+ name: No Survey Template no vars
+ organization:
+ name: Satellite
+ type: organization
+ type: job_template
+ name: Admin
+ type: role
+ - content_object:
+ name: Survey Template with vars no org
+ organization:
+ name: Satellite
+ type: organization
+ type: job_template
+ name: Admin
+ type: role
+ - content_object:
+ name: workflow_test_template
+ organization:
+ name: Satellite
+ type: organization
+ type: job_template
+ name: Admin
+ type: role
+ - content_object:
+ credential_type:
+ kind: ssh
+ name: Machine
+ type: credential_type
+ name: Demo Credential
+ organization:
+ type: credential
+ name: Admin
+ type: role
+ - name: System Administrator
+ type: role
+...
diff --git a/tests/configs_export_model/inventory_export.yml b/tests/configs_export_model/inventory_export.yml
index 833b94bbf..529271de9 100644
--- a/tests/configs_export_model/inventory_export.yml
+++ b/tests/configs_export_model/inventory_export.yml
@@ -1,5 +1,5 @@
---
-controller_inventories:
+inventory:
- name: 2nd Testing Inventory
description: ''
kind: ''
@@ -39,4 +39,20 @@ controller_inventories:
type: organization
name: satlab-admin-inventory
type: inventory
+ - name: localhost
+ description: inventory for localhost
+ organization:
+ name: Satellite
+ - name: RHVM-01
+ organization:
+ name: Satellite
+ description: created by Ansible Playbook - for RHVM-01
+ variables:
+ site_subnet: "{% raw %}{ % if site == 'SITE-2' %}10.200.{ % else %}10.100.{ % endif%}{% endraw %}"
+ remote_subnet: "{% raw %}{ % if site == 'SITE-2' %}10.100.{ % else %}10.200.{ % endif%}{% endraw %}"
+ - name: Demo Inventory
+ organization:
+ name: Default
+ type: organization
+ prevent_instance_group_fallback: false
...
diff --git a/tests/configs_export_model/inventory_sources_export.yml b/tests/configs_export_model/inventory_sources_export.yml
index 88a9fd423..30d941cb6 100644
--- a/tests/configs_export_model/inventory_sources_export.yml
+++ b/tests/configs_export_model/inventory_sources_export.yml
@@ -1,5 +1,5 @@
---
-controller_inventory_sources:
+inventory_sources:
- name: test
description: ''
source: scm
diff --git a/tests/configs_export_model/job_templates_export.yml b/tests/configs_export_model/job_templates_export.yml
index 06c2a407a..55b5344b9 100644
--- a/tests/configs_export_model/job_templates_export.yml
+++ b/tests/configs_export_model/job_templates_export.yml
@@ -1,5 +1,5 @@
---
-controller_templates:
+job_templates:
- name: No Survey Template no vars
description: ''
job_type: run
diff --git a/tests/configs_export_model/notifications_templates_export.yml b/tests/configs_export_model/notifications_templates_export.yml
index 7a79302bd..fa2db115e 100644
--- a/tests/configs_export_model/notifications_templates_export.yml
+++ b/tests/configs_export_model/notifications_templates_export.yml
@@ -1,5 +1,5 @@
---
-controller_notifications:
+notification_templates:
- name: Email notification
description: Send out emails for tower jobs
notification_type: email
diff --git a/tests/configs_export_model/organizations_export.yml b/tests/configs_export_model/organizations_export.yml
index dc85ca647..4d0d3834c 100644
--- a/tests/configs_export_model/organizations_export.yml
+++ b/tests/configs_export_model/organizations_export.yml
@@ -1,5 +1,5 @@
---
-controller_organizations:
+organizations:
- name: Satellite
description: Satellite
max_hosts: 0
@@ -13,6 +13,9 @@ controller_organizations:
- name: Default
description: Default
max_hosts: 0
+ default_environment:
+ name: My EE
+ type: execution_environment
custom_virtualenv: null
related:
notification_templates_started: []
diff --git a/tests/configs_export_model/projects_export.yml b/tests/configs_export_model/projects_export.yml
index 3ad161db1..190de48bd 100644
--- a/tests/configs_export_model/projects_export.yml
+++ b/tests/configs_export_model/projects_export.yml
@@ -1,7 +1,7 @@
---
controller_configuration_projects_async_retries: 60
controller_configuration_projects_async_delay: 2
-controller_projects:
+projects:
- name: Tower Config Testing
description: ''
local_path: _48__controller_config_testing
@@ -39,12 +39,6 @@ controller_projects:
type: organization
name: irc-satqe-chat-notification
type: notification_template
- natural_key:
- organization:
- name: Satellite
- type: organization
- name: Tower Config Testing
- type: project
- name: Tower Config
description: ''
local_path: _52__controller_config
@@ -73,10 +67,30 @@ controller_projects:
type: organization
name: irc-satqe-chat-notification
type: notification_template
- natural_key:
- organization:
- name: Satellite
- type: organization
- name: Tower Config
- type: project
+ - name: Test Project
+ scm_type: git
+ scm_url: https://github.com/ansible/tower-example.git
+ scm_branch: master
+ scm_clean: true
+ description: Test Project 1
+ organization:
+ name: Default
+ wait: true
+ update_project: true
+ - name: Demo Project
+ scm_type: git
+ scm_url: https://github.com/ansible/tower-example.git
+ scm_branch: master
+ scm_clean: true
+ description: Test Project 1
+ organization:
+ name: Default
+ wait: true
+ update_project: true
+ - name: Test Project 2
+ scm_type: git
+ scm_url: https://github.com/ansible/ansible-examples.git
+ description: Test Project 2
+ organization:
+ name: Default
...
diff --git a/tests/configs_export_model/teams_export.yml b/tests/configs_export_model/teams_export.yml
index 46271cd5e..d27097cd2 100644
--- a/tests/configs_export_model/teams_export.yml
+++ b/tests/configs_export_model/teams_export.yml
@@ -1,5 +1,5 @@
---
-controller_teams:
+teams:
- name: team1
description: ''
organization:
@@ -107,4 +107,10 @@ controller_teams:
type: organization
name: team1
type: team
+ - name: satellite-qe
+ organization:
+ name: Satellite
+ - name: satlab-admin
+ organization:
+ name: Satellite
...
diff --git a/tests/configs_export_model/users_export.yml b/tests/configs_export_model/users_export.yml
index 71e31ab76..1bc2f8c7b 100644
--- a/tests/configs_export_model/users_export.yml
+++ b/tests/configs_export_model/users_export.yml
@@ -1,5 +1,5 @@
---
-controller_user_accounts:
+users:
- username: AWX-Collection-tests-controller_role-user
first_name: Joe
last_name: User
@@ -32,4 +32,6 @@ controller_user_accounts:
natural_key:
username: AWX-Collection-tests-controller_role-user-ClPzjxrRTIwcOCvO
type: user
+ - username: controller_user
+ is_superuser: true
...
diff --git a/tests/configs_export_model/workflows.yml b/tests/configs_export_model/workflows.yml
index 2ad0680d9..6e91db8ad 100644
--- a/tests/configs_export_model/workflows.yml
+++ b/tests/configs_export_model/workflows.yml
@@ -1,5 +1,5 @@
---
-controller_workflows:
+workflow_job_templates:
- name: Complicated workflow schema
description: a complicated workflow
extra_vars: {}
diff --git a/tests/configure_controller.yml b/tests/configure_controller.yml
index efd00eea6..3f3f5c6b9 100644
--- a/tests/configure_controller.yml
+++ b/tests/configure_controller.yml
@@ -48,7 +48,7 @@
- name: Wait for Controller to come up
ansible.builtin.uri:
- url: "https://{{ controller_hostname }}/api/v2/ping"
+ url: "https://{{ controller_hostname }}/api/v2/ping/"
status_code: 200
validate_certs: "{{ controller_validate_certs }}"
register: result
@@ -101,6 +101,14 @@
ansible.builtin.include_tasks: "./tasks/ad_hoc_cancel.yml"
when: controller_ad_hoc_commands is defined
+ - name: Launch Controller Bulk Hosts
+ ansible.builtin.include_role:
+ name: bulk_host_create
+ vars:
+ controller_bulk_hosts: "{{ temp_controller_bulk_hosts }}"
+ when:
+ - controller_bulk_launch_jobs is defined
+
- name: Launch Controller Jobs
ansible.builtin.include_role:
name: job_launch
@@ -123,6 +131,25 @@
controller_cancel_jobs: "{{ tmp_jobs.results | map(attribute='ansible_facts.tmp_job') | list }}"
when: launched_controller_jobs is defined
+ - name: Find Job ID's
+ ansible.builtin.debug:
+ var: __job_templates_job_async_result
+
+ - name: Launch Controller Bulk Jobs
+ ansible.builtin.include_role:
+ name: bulk_job_launch
+ vars:
+ controller_bulk_hosts: "{{ temp_controller_bulk_hosts }}"
+ controller_bulk_launch_jobs:
+ - name: My Bulk Job Launch
+ jobs:
+ - unified_job_template: "{{ __job_templates_job_async_result.results[0].id }}"
+ - unified_job_template: "{{ __job_templates_job_async_result.results[1].id }}"
+ organization: Default
+ wait: false
+ when:
+ - controller_bulk_launch_jobs is defined
+
- name: Launch Controller workflows
ansible.builtin.include_role:
name: workflow_launch
@@ -141,7 +168,7 @@
controller_password: "{{ controller_password }}"
controller_host: "{{ controller_hostname }}"
validate_certs: "{{ controller_validate_certs }}"
- ignore_errors: true ## noqa ignore-errors
+ ignore_errors: true # noqa ignore-errors
- name: Get the organization ID
ansible.builtin.set_fact:
@@ -154,13 +181,13 @@
- name: "Error out on empty list"
ansible.builtin.set_fact:
- error_empty_diff: "{{ lookup('controller_object_diff', api_list=controller_api_results, compare_list=differential_test_items, warn_on_empty_api=false) }}"
+ error_empty_diff: "{{ query('controller_object_diff', api_list=controller_api_results, compare_list=differential_test_items, warn_on_empty_api=false) }}"
ignore_errors: true
register: error_results
- name: "Warn out on empty list"
ansible.builtin.set_fact:
- warn_empty_diff: "{{ lookup('controller_object_diff', api_list=controller_api_results, compare_list=differential_test_items) }}"
+ warn_empty_diff: "{{ query('controller_object_diff', api_list=controller_api_results, compare_list=differential_test_items) }}"
register: warn_results
- name: "Assert that the empty list error correctly"
diff --git a/tests/configure_controller_export_model.yml b/tests/configure_controller_export_model.yml
index ce881e141..5b9486c0b 100644
--- a/tests/configure_controller_export_model.yml
+++ b/tests/configure_controller_export_model.yml
@@ -60,16 +60,57 @@
roles:
- - {role: organizations, when: controller_organizations is defined, tags: organizations}
- - {role: users, when: controller_user_accounts is defined, tags: users}
- - {role: teams, when: controller_teams is defined, tags: teams}
- - {role: credential_types, when: controller_credential_types is defined, tags: credential_types}
- - {role: credentials, when: controller_credentials is defined, tags: credentials}
- - {role: inventories, when: controller_inventories is defined, tags: inventories}
- - {role: inventory_sources, when: controller_inventory_sources is defined, tags: inventory_sources}
- - {role: projects, when: controller_projects is defined, tags: projects}
- - {role: project_update, when: controller_projects is defined, tags: projects}
- - {role: job_templates, when: controller_templates is defined, tags: job_templates}
- - {role: workflow_job_templates, when: controller_workflows is defined, tags: workflow_job_templates}
- - {role: notification_templates, when: controller_notifications is defined, tags: notification_templates}
+ - {role: organizations, when: organizations is defined, tags: organizations}
+ - {role: users, when: users is defined, tags: users}
+ - {role: teams, when: teams is defined, tags: teams}
+ - {role: credential_types, when: credential_types is defined, tags: credential_types}
+ - {role: credentials, when: credentials is defined, tags: credentials}
+ - {role: inventories, when: inventory is defined, tags: inventories}
+ - {role: inventory_sources, when: inventory_sources is defined, tags: inventory_sources}
+ - {role: projects, when: projects is defined, tags: projects}
+ - {role: project_update, when: projects is defined, tags: projects}
+ - {role: job_templates, when: job_templates is defined, tags: job_templates}
+ - {role: workflow_job_templates, when: workflow_job_templates is defined, tags: workflow_job_templates}
+ - {role: notification_templates, when: notification_templates is defined, tags: notification_templates}
+
+ tasks:
+ # Need to install inside the venv for collection testing.
+ - name: Install awxkit python package
+ ansible.builtin.pip:
+ name: awxkit
+ version: 22.3.0
+
+ - name: Export workflow job template
+ infra.controller_configuration.controller_export_diff:
+ all: true
+ compare_items:
+ organizations: "{{ organizations }}"
+ projects: "{{ projects }}"
+ credential_types: "{{ credential_types }}"
+ credentials: "{{ credentials }}"
+ inventory: "{{ inventory }}"
+ inventory_sources: "{{ inventory_sources }}"
+ notification_templates: "{{ notification_templates }}"
+ teams: "{{ teams }}"
+ users: "{{ users }}"
+ job_templates: "{{ job_templates }}"
+ with_present: false
+ controller_host: "{{ controller_hostname }}"
+ controller_username: "{{ controller_username }}"
+ controller_password: "{{ controller_password }}"
+ validate_certs: "{{ controller_validate_certs }}"
+ register: export_results
+
+ - name: Export output
+ ansible.builtin.debug:
+ var: export_results.difference
+
+ - name: Differential_expected output
+ ansible.builtin.debug:
+ var: differential_expected
+
+ - name: "Assert that the expected results match for {{ differential_item.name }}"
+ ansible.builtin.assert:
+ that:
+ - differential_expected == export_results.difference
...
diff --git a/tests/tasks/differential.yml b/tests/tasks/differential.yml
index 261f51419..b48b9f0d4 100644
--- a/tests/tasks/differential.yml
+++ b/tests/tasks/differential.yml
@@ -1,11 +1,11 @@
---
- name: "Get the API list in the Default Organization of all {{ differential_item.name }}"
ansible.builtin.set_fact:
- controller_api_results: "{{ lookup(controller_api_plugin, differential_item.name, query_params={'organization': controller_organization_id.id}, host=controller_hostname, username=controller_username, password=controller_password, verify_ssl=false) }}"
+ controller_api_results: "{{ query(controller_api_plugin, differential_item.name, query_params={'organization': controller_organization_id.id}, host=controller_hostname, username=controller_username, password=controller_password, verify_ssl=false) }}"
- name: "Find the difference between what is on the Controller versus curated list of {{ differential_item.name }}"
ansible.builtin.set_fact:
- set_absent_diff: "{{ lookup('controller_object_diff', api_list=controller_api_results, compare_list=differential_item.differential_test_items, with_present=differential_item.with_present) }}"
+ set_absent_diff: "{{ query('controller_object_diff', api_list=controller_api_results, compare_list=differential_item.differential_test_items, with_present=differential_item.with_present) | flatten }}"
- name: Display set_absent_diff
ansible.builtin.debug:
@@ -18,7 +18,7 @@
- name: "Assert that the expected results match for {{ differential_item.name }}"
ansible.builtin.assert:
that:
- - set_absent_diff == differential_item.expected_test_result
+ - set_absent_diff == differential_item.expected_test_result
- name: Run differential applications
ansible.builtin.include_role:
diff --git a/tests/templated_role_example/README.md b/tests/templated_role_example/README.md
new file mode 100644
index 000000000..fa223bf11
--- /dev/null
+++ b/tests/templated_role_example/README.md
@@ -0,0 +1,112 @@
+# controller_configuration.***********
+
+## Description
+
+An Ansible Role to create******* on Ansible Controller.
+
+## Requirements
+
+ansible-galaxy collection install -r tests/collections/requirements.yml to be installed
+Currently:
+ awx.awx
+ or
+ ansible.controller
+
+## Variables
+
+### Authentication
+
+|Variable Name|Default Value|Required|Description|Example|
+|:---|:---:|:---:|:---|:---|
+|`controller_state`|"present"|no|The state all objects will take unless overridden by object default|'absent'|
+|`controller_hostname`|""|yes|URL to the Ansible Controller Server.|127.0.0.1|
+|`controller_validate_certs`|`True`|no|Whether or not to validate the Ansible Controller Server's SSL certificate.||
+|`controller_username`|""|no|Admin User on the Ansible Controller Server. Either username / password or oauthtoken need to be specified.||
+|`controller_password`|""|no|Controller Admin User's password on the Ansible Controller Server. This should be stored in an Ansible Vault at vars/controller-secrets.yml or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.||
+|`controller_oauthtoken`|""|no|Controller Admin User's token on the Ansible Controller Server. This should be stored in an Ansible Vault at or elsewhere and called from a parent playbook. Either username / password or oauthtoken need to be specified.|||
+|`controller_************`|`see below`|yes|Data structure describing your organization or organizations Described below.||
+
+### Secure Logging Variables
+
+The following Variables compliment each other.
+If Both variables are not set, secure logging defaults to false.
+The role defaults to False as normally the add ******* task does not include sensitive information.
+controller_configuration_*******_secure_logging defaults to the value of controller_configuration_secure_logging if it is not explicitly called. This allows for secure logging to be toggled for the entire suite of controller configuration roles with a single variable, or for the user to selectively use it.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_*******_secure_logging`|`False`|no|Whether or not to include the sensitive ******* role tasks in the log. Set this value to `True` if you will be providing your sensitive values from elsewhere.|
+|`controller_configuration_secure_logging`|`False`|no|This variable enables secure logging as well, but is shared across multiple roles, see above.|
+
+### Asynchronous Retry Variables
+
+The following Variables set asynchronous retries for the role.
+If neither of the retries or delay or retries are set, they will default to their respective defaults.
+This allows for all items to be created, then checked that the task finishes successfully.
+This also speeds up the overall role.
+
+|Variable Name|Default Value|Required|Description|
+|:---:|:---:|:---:|:---:|
+|`controller_configuration_async_retries`|30|no|This variable sets the number of retries to attempt for the role globally.|
+|`controller_configuration_*******_async_retries`|`{{ controller_configuration_async_retries }}`|no|This variable sets the number of retries to attempt for the role.|
+|`controller_configuration_async_delay`|1|no|This sets the delay between retries for the role globally.|
+|`controller_configuration_*******_async_delay`|`controller_configuration_async_delay`|no|This sets the delay between retries for the role.|
+|`controller_configuration_async_dir`|`null`|no|Sets the directory to write the results file for async tasks. The default value is set to `null` which uses the Ansible Default of `/root/.ansible_async/`.|
+
+## Data Structure
+
+### ************ Variables
+
+|Variable Name|Default Value|Required|Type|Description|
+|:---:|:---:|:---:|:---:|:---:|
+|`name`|""|yes|str|Name of Job Template|
+|`new_name`|""|str|no|Setting this option will change the existing name (looked up via the name field).|
+|`description`|`False`|no|str|Description to use for the job template.|
+
+|`state`|`present`|no|str|Desired state of the resource.|
+
+### Standard Project Data Structure
+
+#### Json Example
+
+```json
+{
+}
+
+```
+
+#### Yaml Example
+
+```yaml
+---
+
+```
+
+## Playbook Examples
+
+### Standard Role Usage
+
+```yaml
+---
+- name: Playbook to configure ansible controller post installation
+ hosts: localhost
+ connection: local
+ # Define following vars here, or in controller_configs/controller_auth.yml
+ # controller_hostname: ansible-controller-web-svc-test-project.example.com
+ # controller_username: admin
+ # controller_password: changeme
+ pre_tasks:
+ - name: Include vars from controller_configs directory
+ include_vars:
+ dir: ./yaml
+ ignore_files: [controller_config.yml.template]
+ extensions: ["yml"]
+ roles:
+ - {role: redhat_cop.controller_configuration.license, when: controller_license is defined}
+```
+
+## License
+
+[MIT](https://github.com/redhat-cop/controller_configuration#licensing)
+
+## Author
diff --git a/tests/templated_role_example/defaults/main.yml b/tests/templated_role_example/defaults/main.yml
new file mode 100644
index 000000000..345082a5e
--- /dev/null
+++ b/tests/templated_role_example/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+controller_configuration_*******_secure_logging: "{{controller_configuration_secure_logging | default('false') }}"
+controller_configuration_***********_async_retries: "{{ controller_configuration_async_retries | default(30) }}"
+controller_configuration_***********_async_delay: "{{ controller_configuration_async_delay | default(1) }}"
+controller_configuration_async_dir: null
+...
diff --git a/tests/templated_role_example/meta/main.yml b/tests/templated_role_example/meta/main.yml
new file mode 100644
index 000000000..a7b559add
--- /dev/null
+++ b/tests/templated_role_example/meta/main.yml
@@ -0,0 +1,46 @@
+---
+galaxy_info:
+ role_name: "**************"
+ author: "************"
+ description: "An Ansible Role to create ************ in Ansible Controller."
+ company: "Red Hat"
+
+ # If the issue tracker for your role is not on github, uncomment the
+ # next line and provide a value
+ # issue_tracker_url: http://example.com/issue/tracker
+ license: "MIT"
+
+ min_ansible_version: "2.8"
+
+ # Optionally specify the branch Galaxy will use when accessing the GitHub
+ # repo for this role. During role install, if no tags are available,
+ # Galaxy will use this branch. During import Galaxy will access files on
+ # this branch. If Travis integration is configured, only notifications for this
+ # branch will be accepted. Otherwise, in all cases, the repo's default branch
+ # (usually master) will be used.
+
+ # github_branch:
+
+ #
+ # platforms is a list of platforms, and each platform has a name and a list of versions.
+ #
+ platforms:
+ - name: "EL"
+ versions:
+ - "all"
+
+ galaxy_tags:
+ - "controller"
+ - "aap"
+ - "awx"
+ - "***************"
+ - "***************s"
+
+collections:
+ - ansible.controller
+ - awx.awx
+
+dependencies: []
+# List your role dependencies here, one per line. Be sure to remove the '[]' above,
+# if you add dependencies to this list.
+...
diff --git a/tests/templated_role_example/tasks/main.yml b/tests/templated_role_example/tasks/main.yml
new file mode 100644
index 000000000..dc9d97782
--- /dev/null
+++ b/tests/templated_role_example/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+# Create Job Template
+- name: Add Controller ***********
+ controller_***********:
+ name: "{{ ***********_item.name }}"
+ new_name: "{{ ***********_item.new_name | default(omit, true) }}"
+ description: "{{ ***********_item.description | default('') }}"
+
+ # Role specific options
+ state: "{{ ***********_item.state | default(controller_state | default('present')) }}"
+ controller_username: "{{ controller_username | default(omit, true) }}"
+ controller_password: "{{ controller_password | default(omit, true) }}"
+ controller_oauthtoken: "{{ controller_oauthtoken | default(omit, true) }}"
+ controller_host: "{{ controller_hostname | default(omit, true) }}"
+ controller_config_file: "{{ controller_config_file | default(omit, true) }}"
+ validate_certs: "{{ controller_validate_certs | default(omit) }}"
+ loop: "{{ controller_************ }}"
+ loop_control:
+ loop_var: "__controller_***********_item"
+ no_log: "{{ controller_configuration_*******_secure_logging }}"
+ when: controller_************ is defined
+ async: 1000
+ poll: 0
+ register: __controller_***********_job_async
+ changed_when: not __controller_***********_job_async.changed
+ vars:
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+
+- name: "Configure *********** | Wait for finish the *********** creation"
+ async_status:
+ jid: "{{ __controller_***********_job_async_results_item.ansible_job_id }}"
+ register: __controller_***********_job_async_result
+ until: __controller_***********_job_async_result.finished
+ retries: "{{ controller_configuration_***********_async_retries }}"
+ delay: "{{ controller_configuration_***********_async_delay }}"
+ loop: "{{ __controller_***********_job_async.results }}"
+ loop_control:
+ loop_var: __controller_***********_job_async_results_item
+ when: __controller_***********_job_async_results_item.ansible_job_id is defined
+ no_log: "{{ controller_configuration_*******_secure_logging }}"
+ vars:
+ ansible_async_dir: '{{ controller_configuration_async_dir }}'
+...
diff --git a/tests/templated_role_example/tests/config/extra_vars.yml b/tests/templated_role_example/tests/config/extra_vars.yml
new file mode 100644
index 000000000..17f4894ac
--- /dev/null
+++ b/tests/templated_role_example/tests/config/extra_vars.yml
@@ -0,0 +1,8 @@
+---
+empty_master_vars:
+ empty_var: "nothing"
+
+survey_extra_vars:
+ example_a: 127.0.0.1
+ example_b: "text"
+...
diff --git a/tests/templated_role_example/tests/test.yml b/tests/templated_role_example/tests/test.yml
new file mode 100644
index 000000000..2040626c8
--- /dev/null
+++ b/tests/templated_role_example/tests/test.yml
@@ -0,0 +1,23 @@
+---
+- name: Add *********** to Controller
+ hosts: localhost
+ connection: local
+ gather_facts: false
+ vars:
+ controller_validate_certs: false
+ controller_hostname: controller.example.com
+ controller_username: admin
+ controller_password: changeme
+
+ collections:
+ - awx.awx
+
+ pre_tasks:
+ - name: Include vars from controller_configs directory
+ include_vars:
+ dir: ./configs
+ extensions: ["yml"]
+
+ roles:
+ - {role: ../.., when: role_*********** is defined}
+...