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'] }}"

Building Execution environments

Back

Home