main.yml
To facillitate the change in code we need to be able to map the organization using its name, we have split the play into the following parts:
- pre_tasks
- roles
- tasks
We will explain why:
pre_tasks
In the pre_tasks, we merge all variables we need to run the first part of the configuration, so that the organizations are defined and have their id.
We include the vars from the workaround.yml, so we can influence the infra.aap_configuration collection.
We set the aap_configuration_dispatcher_roles variable to the first part of our own creation.
roles
For simplicity, we just call the infra.aap_configuration.dispatch role
and with the variable modified, it runs just a few roles and stops where we need it to.
tasks
Here we first merge and prepare the rest of the variables for the configuration.
In 2.5 we had to add some tasks to ensure the mappings of the organization worked correctly, this is no longer needed.
The last task is running the dispatch role and letting it finish
Preparation for recovery
Configuration as code is ment to be able to recover from a disaster, this is no different for the automation platform. We do not want to spend a lot of time doing this, we want to recover without doing a lot of steps or manual work. The way we built the configuration, with everything split into manageable parts, leaves us with a lot of repositories that we must run through the pipeline to restore everything.
To be able to run this in just one job, we must prepare..
For rebuiding the execution environments, we need a current ansible.cfg to be able to install collections during the build. So we add a little code to this playbook to create the ansible.cgf during each run on the automation platform server.
---
- name: Configure rhaap platform base
hosts: "{{ instance | default('localhost') }}"
connection: local
gather_facts: false
vars:
vault_url: <vault service url>
pre_tasks:
# The workaround changes the order for the default role_list in the dispatch role
# Not only the order is fixed, but also the complete list is split into 2 lists
# so we can do some tasks in between to fix things
- name: Include temporary workaround vars
ansible.builtin.include_vars:
file: workarounds.yml
# fetch the configuration admin credentials from the external secrets vault (openbao in our case)
- name: Get secrets
community.hashi_vault.vault_kv2_get:
url: "{{ vault_url }}"
token: "{{ vault_token }}"
namespace: "{{ branch_name }}/{{ org_name }}"
engine_mount_point: kv
path: "rhaap_admin"
register: secrets
no_log: true
- name: Set rhaap facts
ansible.builtin.set_fact:
aap_hostname: "{{ secrets['secret']['hostname'] }}"
aap_username: "{{ secrets['secret']['username'] }}"
aap_password: "{{ secrets['secret']['password'] }}"
aap_validate_certs: "{{ secrets['secret']['validate_certs'] }}"
ah_hostname: "https://{{ secrets['secret']['fqdn'] }}"
ah_validate_certs: "{{ secrets['secret']['validate_certs'] }}"
ah_username: "{{ secrets['secret']['username'] }}"
ah_password: "{{ secrets['secret']['password'] }}"
cloud_token: "{{ secrets['secret']['cloud_token'] }}"
cfg_hostname: "{{ secrets['secret']['fqdn'] }}"
cfg_password: "{{ secrets['secret']['password'] }}"
cfg_redhat_subscription_username: "{{ secrets['secret']['rh_sub_username'] }}"
cfg_redhat_subscription_password: "{{ secrets['secret']['rh_sub_password'] }}"
no_log: true
# Set the first set of vars for the dispatch role to configure the Gateway
# Hub and controller will follow in the next steps
# first we fetch the list of local users for the organizations from the vault
# and create the gateway_user_accounts variable
# These users are stored in one secret "base_users" in the secrets vault, the key/value pairs
# are the username and password for that user, so this one secret holds the complete list of
# local users on the gateway without the security risk of pushing them into a git repository.
- name: Read secrets from vault
ansible.builtin.uri:
url: "{{ vault_url }}/v1/kv/data/base_users"
method: GET
headers:
X-Vault-Token: "{{ vault_token }}"
X-Vault-Namespace: "{{ branch_name }}/{{ org_name }}"
Content-type: "application/json"
timeout: 10
validate_certs: false
register: rsecret
- name: Set the content var
ansible.builtin.set_fact:
_content: "{{ rsecret['json']['data']['data'] }}"
aap_user_accounts: []
- name: Create gateway_users variable from vault
ansible.builtin.set_fact:
aap_user_accounts: "{{ aap_user_accounts + [{'username': user.key, 'password': user.value, 'update_secrets': 'false', 'email': '' }] }}"
loop: "{{ _content | dict2items }}"
loop_control:
loop_var: user
# Set the first set of vars for the dispatch role to configure the Gateway
# Hub and controller will follow in the next steps
- name: Set the gateway vars
ansible.builtin.set_fact:
configure_hub: "{{ run_hub_config | bool }}"
aap_configuration_secure_logging: false
aap_applications: >
{{ aap_applications_all |
community.general.lists_mergeby(vars['aap_applications_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_authenticator_maps: >
{{ gateway_authenticator_maps_all |
community.general.lists_mergeby(vars['gateway_authenticator_maps_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_authenticators: >
{{ gateway_authenticators_all |
community.general.lists_mergeby(vars['gateway_authenticators_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_http_ports: >
{{ gateway_http_ports_all |
community.general.lists_mergeby(vars['gateway_http_ports_' + branch_name],
'name', recursive=true, list_merge='append') }}
aap_organizations: >
{{ gateway_organizations_all |
community.general.lists_mergeby(vars['gateway_organizations_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_routes: >
{{ gateway_routes_all |
community.general.lists_mergeby(vars['gateway_routes_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_service_clusters: >
{{ gateway_service_clusters_all |
community.general.lists_mergeby(vars['gateway_service_clusters_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_service_keys: >
{{ gateway_service_keys_all |
community.general.lists_mergeby(vars['gateway_service_keys_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_service_nodes: >
{{ gateway_service_nodes_all |
community.general.lists_mergeby(vars['gateway_service_nodes_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_services: >
{{ gateway_services_all |
community.general.lists_mergeby(vars['gateway_services_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_settings: >
{{ gateway_settings_all |
community.general.lists_mergeby(vars['gateway_settings_' + branch_name],
'name', recursive=true, list_merge='append') }}
aap_teams: >
{{ aap_teams_all |
community.general.lists_mergeby(vars['aap_teams_' + branch_name],
'name', recursive=true, list_merge='append') }}
gateway_role_user_assignments: >
{{ gateway_role_user_assignments_all |
community.general.lists_mergeby(vars['gateway_role_user_assignments_' + branch_name],
'user', recursive=true, list_merge='append') }}
gateway_role_team_assignments: >
{{ gateway_role_team_assignments_all |
community.general.lists_mergeby(vars['gateway_role_team_assignments_' + branch_name],
'team', recursive=true, list_merge='append') }}
hub_team_roles: >
{{ hub_team_roles_all |
community.general.lists_mergeby( vars['hub_team_roles_' + branch_name],
'team', recursive=true, list_merge='append' ) }}
# Create the second set of variables to configure the automation hub
- name: Set the automation hub vars
ansible.builtin.set_fact:
ee_image_push: true
ee_validate_certs: false
ee_create_ansible_config: false
hub_collection_repositories: >
{{ hub_collection_repositories_all |
community.general.lists_mergeby( vars['hub_collection_repositories_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
hub_collection_remotes: >
{{ hub_collection_remotes_all |
community.general.lists_mergeby( vars['hub_collection_remotes_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
hub_namespaces: >
{{ hub_namespaces_all |
community.general.lists_mergeby( vars['hub_namespaces_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
hub_collections: >
{{ hub_collections_all |
community.general.lists_mergeby( vars['hub_collections_' + branch_name],
'collection_name', recursive=true, list_merge='append' ) }}
hub_ee_images: >
{{ hub_ee_images_all |
community.general.lists_mergeby( vars['hub_ee_images_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
hub_ee_registries: >
{{ hub_ee_registries_all |
community.general.lists_mergeby( vars['hub_ee_registries_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
hub_ee_repositories: >
{{ hub_ee_repositories_all |
community.general.lists_mergeby( vars['hub_ee_repositories_' + branch_name],
'name', recursive=true, list_merge='append' ) }}
when: configure_hub
- name: Set the role-list to run first
ansible.builtin.set_fact:
aap_configuration_dispatcher_roles: "{{ aap_configuration_dispatcher_roles_1 }}"
roles:
- infra.aap_configuration.dispatch
tasks:
# Apply a workaround for the infra collection not mapping hub roles
# using the hub_team_roles variable
- name: Apply the hub roles when defined
ansible.hub.team_roles:
team: "{{ _hub_role.team }}"
role: "{{ _hub_role.role }}"
state: "{{ _hub_role.state | default(present) }}"
ah_host: "{{ secrets['secret']['fqdn'] }}"
validate_certs: "{{ secrets['secret']['validate_certs'] }}"
ah_username: "{{ secrets['secret']['username'] }}"
ah_password: "{{ secrets['secret']['password'] }}"
loop: "{{ hub_team_roles }}"
loop_control:
loop_var: _hub_role
when: hub_team_roles | length > 0
- name: Set the role-list to run second stage
ansible.builtin.set_fact:
aap_configuration_dispatcher_roles: "{{ aap_configuration_dispatcher_roles_2 }}"
- name: Download controller_license file
ansible.builtin.get_url:
url: "{{ manifest_url }}"
dest: /tmp/manifest_rhaap.zip
mode: '0655'
# Generate a hub token to use for the galaxy credentials in controller
# This token is not echoed, so for use in ansible.cfg, you must use a new account
# and create a token for that account after configuration.
- name: Create a new token using username/password
ansible.hub.ah_token:
state: present
ah_host: "{{ aap_hostname }}"
ah_username: coll_get
ah_password: "{{ _content['coll_get'] }}"
validate_certs: false
no_log: true
# Create the set of variables to configure the controller
- name: Set the controller vars
ansible.builtin.set_fact:
aap_configuration_secure_logging: false
controller_license: "{{ controller_license_all | combine(vars['controller_license_' + branch_name], recursive=True) }}"
controller_credential_input_sources: >
{{ controller_credential_input_sources_all |
community.general.lists_mergeby(vars['controller_credential_input_sources_' + branch_name],
'source_credential', recursive=true, list_merge='append') }}
controller_credential_types: >
{{ controller_credential_types_all |
community.general.lists_mergeby(vars['controller_credential_types_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_execution_environments: >
{{ controller_execution_environments_all |
community.general.lists_mergeby(vars['controller_execution_environments_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_hosts: >
{{ controller_hosts_all |
community.general.lists_mergeby(vars['controller_hosts_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_instance_groups: >
{{ controller_instance_groups_all |
community.general.lists_mergeby(vars['controller_instance_groups_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_inventory_sources: >
{{ controller_inventory_sources_all |
community.general.lists_mergeby(vars['controller_inventory_sources_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_inventories: >
{{ controller_inventories_all |
community.general.lists_mergeby(vars['controller_inventories_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_labels: >
{{ controller_labels_all |
community.general.lists_mergeby(vars['controller_labels_' + branch_name],
'name', recursive=true, list_merge='append') }}
aap_organizations: >
{{ aap_organizations_all |
community.general.lists_mergeby(vars['aap_organizations_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_notifications: >
{{ controller_notifications_all |
community.general.lists_mergeby(vars['controller_notifications_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_projects: >
{{ controller_projects_all |
community.general.lists_mergeby(vars['controller_projects_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_settings: >
{{ controller_settings_all |
community.general.lists_mergeby(vars['controller_settings_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_schedules: >
{{ controller_schedules_all |
community.general.lists_mergeby(vars['controller_schedules_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_templates: >
{{ controller_templates_all |
community.general.lists_mergeby(vars['controller_templates_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_roles: >
{{ controller_roles_all |
community.general.lists_mergeby(vars['controller_roles_' + branch_name],
'name', recursive=true, list_merge='append') }}
controller_workflows: >
{{ controller_workflows_all |
community.general.lists_mergeby(vars['controller_workflows_' + branch_name],
'name', recursive=true, list_merge='append') }}
# To translate the token variable in the configuration file, we must generate
# these somewhat different.
- name: Set credentials_var for dev
ansible.builtin.set_fact:
controller_credentials: "{{ controller_credentials_all + controller_credentials_dev }}"
when: branch_name == 'dev'
- name: Set credentials_var for prod
ansible.builtin.set_fact:
controller_credentials: "{{ controller_credentials_all + controller_credentials_prod }}"
when: branch_name == 'prod'
# Create the set of variables to configure the controller
- name: Set the eda vars
ansible.builtin.set_fact:
eda_credential_types: >
{{ eda_credential_types_all |
community.general.lists_mergeby(vars['eda_credential_types_' + branch_name],
'name', recursive=true, list_merge='append') }}
eda_decision_environments: >
{{ eda_decision_environments_all |
community.general.lists_mergeby(vars['controller_workflows_' + branch_name],
'name', recursive=true, list_merge='append') }}
- name: Run second part of the base config
ansible.builtin.include_role:
name: infra.aap_configuration.dispatch
# Apply a workaround for the infra collection not mapping instance_group roles
# using the controller_roles variable
- name: Apply the controller roles when defined
ansible.controller.role:
teams: "{{ _controller_role.teams }}"
role: "{{ _controller_role.role }}"
instance_groups: "{{ _controller_role.instance_groups }}"
state: "{{ _controller_role.state }}"
controller_host: "{{ secrets['secret']['fqdn'] }}"
validate_certs: "{{ secrets['secret']['validate_certs'] }}"
controller_username: "{{ secrets['secret']['username'] }}"
controller_password: "{{ secrets['secret']['password'] }}"
loop: "{{ controller_instance_group_roles }}"
loop_control:
loop_var: _controller_role
when: controller_instance_group_roles | length > 0
# The code added here is to create a current ansible.cfg with the correct token
# for the current itteration of the rhaap platform, we need this for recovery.
- name: Set token_var to pass to ansible.cfg
ansible.builtin.set_fact:
ansible_token: "{{ ah_token['token'] }}"
# We write a current ansible.cfg to the server
# we will be using this for subsequent (EE) pipelines during recovery.
- name: Prepare to pass the ansible.cfg to the host
ansible.builtin.add_host:
groups: rhaap_server
hostname: "{{ cfg_hostname }}"
ansible_user: ansible
ansible_password: "{{ lookup('community.hashi_vault.hashi_vault', 'secret=kv/data/rhaap_admin:cfg_password }}"
- name: Write ansible.cfg
hosts: rhaap_server
# As the pipeline image has no ansible keys setup, we must disable keychecking
vars:
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
vault_url: <vault service url>
tasks:
- name: Set token_var to pass to ansible.cfg
ansible.builtin.set_fact:
ansible_token: "{{ hostvars['aap_dev']['ansible_token'] }}"
- name: Template the new ansible.cfg
ansible.builtin.template:
src: ansible.cfg.j2
dest: /etc/ansible/ansible.cfg
mode: '0644'
owner: root
group: root
become: true
# The task below writes a current version of ansible.cfg to a webserver
# where pipelines can pick it up without having to modify the repositories
- name: Get the collection download secret
community.hashi_vault.vault_kv2_get:
url: "{{ vault_url }}"
token: "{{ vault_token }}"
namespace: "{{ branch_name }}/{{ org_name }}"
engine_mount_point: kv
path: "website_owner"
register: _wo_secret
no_log: true
- name: Template the new ansible.cfg to webserver
ansible.builtin.template:
src: ansible.cfg.j2
dest: "/var/www/localhost/htdocs/{{ branch_name }}_ansible.cfg"
mode: '0644'
owner: ansible
group: ansible
delegate_to: web.dev.lab
vars:
ansible_ssh_user: "{{ _wo_secret['secret']['username'] }}"
ansible_ssh_password: "{{ _wo_secret['secret']['password'] }}"