CaC for EDA (Event Driven Ansible)
EDA is the Event Driven Ansible controller, which enables you to import monitoring
events and respond automatically, by running a remedial playbook.
Recently, it has become possible to create and maintain a configuration as code
template and repository for the EDA as well. The necessary collection for this has
received an important update from the community.
The collection required for this:
- infra.eda_configuration
If you're searching the web, you'll need to search for:
- redhat_cop.eda_configuration
Then you will also find all the accompanying documentation, which I have used here. Of course I used my trick to make things a bit easier. Because the trick is always the same, it is now easier to understand. Not much is recorded in the configuration as code for the EDA, because the most complex work is in the projects used by EDA. As usual, we start with a brief explanation of the pipeline.
The CaC pipeline
# Pull the ansible config as code image
image: localhost:5000/ansible-image:1.1
# List of pipeline stages
stages:
- lint
- Configure eda controller
lint_and_push:
tags:
- shared
stage: lint
rules:
- if: '$CI_COMMIT_REF_NAME != "dev"
&& $CI_COMMIT_REF_NAME != "test"
&& $CI_COMMIT_REF_NAME != "accp"
&& $CI_COMMIT_REF_NAME != "prod"'
script:
- echo "From pipeline - Start linting on '$CI_COMMIT_REF_NAME'"
- ansible-lint
configure_from_merge:
tags:
- shared
stage: Configure eda controller
rules:
- if: '($CI_COMMIT_BRANCH == "dev" ||
$CI_COMMIT_BRANCH == "test" ||
$CI_COMMIT_BRANCH == "accp" ||
$CI_COMMIT_BRANCH == "prod") &&
$CI_PIPELINE_SOURCE == "push" &&
$CI_COMMIT_MESSAGE =~ /Merge branch/i'
script:
- echo "Perform merge to '$CI_COMMIT_BRANCH' Environment"
- TOKEN_VAR=$(echo "AUTOMATION_HUB_TOKEN_${CI_COMMIT_BRANCH}" | tr [:lower:]
[:upper:])
- ansible-playbook main.yml
-i inventory.yaml
-e instance=controller_$CI_COMMIT_BRANCH
-e ahub_token=$(printenv $TOKEN_VAR)
-e branch_name=$CI_COMMIT_BRANCH
--vault-password-file <(echo ${VAULT_PASSWORD})
configure_from_trigger:
tags:
- shared
stage: Configure eda controller
rules:
- if: '$CI_PIPELINE_SOURCE == "pipeline"'
script:
- echo "Pipeline triggered by '$CI_PIPELINE_SOURCE' ref"
- echo "From pipeline - Start controller recovery on '$CI_COMMIT_REF_NAME'
Environment"
- ansible-playbook main.yml
-i inventory.yaml
-e instance=eda_$CI_COMMIT_REF_NAME
-e branch_name=$CI_COMMIT_REF_NAME
--vault-password-file <(echo ${VAULT_PASSWORD})
As can be read above, the pipeline is the most complex we have seen so far, this is the pipeline that we actually use. The pipelines in the previous chapters were evolutions to this version. By using "rules", we are pretty much in the future in gitlab, because the "only" tag is going to disappear. For the rest, we mainly make sure that when a feature branch is pushed, a linting of the code is always done. If the linting is successful, the update can be merged into the "dev" branch/environment, through a merge_request, which starts the configuration on the merge commit, by running the second part of the pipeline. If an update is made to a branch via a merge request, the second part of the pipeline will be executed. The last part of the pipeline is dedicated to the recovery from chapter 12, then this step of the pipeline will be executed. Because this configuration also contains secrets that give access to the environment, ansible-vault is also used. That is why a vault password must be provided in order to decrypt the secrets. This vault password is configured as a secret variable on the repository.
The git repository
The configuration as code of the eda also requires a git repository. This repository is similar in content and structure to the other repositories.
.
├── group_vars
│ ├── all
│ │ ├── credentials.yaml
│ │ ├── decision_environments.yaml
│ │ ├── projects.yaml
│ │ ├── rulebook_activations.yaml
│ │ ├── users.yaml
│ │ └── user_tokens.yaml
│ ├─ dev
│ │ ├── credentials.yaml
│ │ ├── decision_environments.yaml
│ │ ├── projects.yaml
│ │ ├── rulebook_activations.yaml
│ │ ├── users.yaml
│ │ └── user_tokens.yaml
│ └── test
│ ├── credentials.yaml
│ ├── decision_environments.yaml
│ ├── projects.yaml
│ ├── rulebook_activations.yaml
│ ├── users.yaml
│ └── user_tokens.yaml
├── host_vars
│ ├── hub_dev
│ │ └── eda_auth.yaml
│ └── hub_test
│ └── eda_auth.yaml
├── inventory.yaml
├── main.yml
└── README.md
You can see that not many files are used for an EDA configuration, the contents of which we will describe below.
credentials.yaml
An EDA installation only has a limited number of credential types, an option to authenticate with username and password is missing. Everything has to be authenticated with so-called tokens. This seems to be a great option, but it is limited in the number of sources that can be used.
---
eda_credentials_dev:
# - name: my_github_user
# description: my GitHub Credential
# credential_type: 'GitHub Personal Access Token'
# username: githubuser
# secret: GITHUBTOKEN
#
- name: superman
description: 'Look mammy, no hands'
credential_type: 'GitLab personal access token'
username: superman
secret: 'klfsk-450980498ba40328dc0d'
- name: Image_cred
description: 'Image pull credential'
credential_type: 'Container Registry'
username: image_pull_user
secret: <vaulted-token>
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| name | "" | yes | str | Credential name. Must be lower case containing only alphanumeric characters and underscores. |
| new_name | "" | no | str | Setting this option will change the existing name (looked up via the name field.) |
| description | "" | no | str | Description to use for the credential. |
| username | "" | yes | str | The username of the credential. |
| secret | "" | yes | str | The token or password for the given username (depending upon the credential type). |
| credential_type | "GitHub Personal Access Token" | yes | str | The type of the credential. |
| state | present | no | str | Desired state of the credential. |
decision_environments.yaml
If you are going to use EDA more, it may be necessary to use specific container images to perform certain checks, just like with a controller. Here, these images can be disclosed to EDA so that they can be retrieved as soon as it is used.
---
eda_decision_environments_dev:
# - name: my_default_de
# description: my default decision environment
# image_url: "image_registry.example.com/default-de:latest"
# credential: my_credential
- name: secret_de_image
description: 'some special check engine'
image_url: "registry.example.com:5000/secret-image:latest"
credential: Image_cred
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| name | "" | yes | str | Decision Environment name. Must be lower case containing only alphanumeric characters and underscores. |
| new_name | "" | no | str | Setting this option will change the existing name (looked up via the name field.) |
| description | "" | no | str | Description to use for the Project. |
| image_url | "" | yes | str | A URL to a a container image to use for the decision environment. |
| credential | "" | no | str | The credential used to access the container registry holding the image. |
| state | present | no | str | Desired state of the decision environment. |
projects.yaml
A project in EDA is a reference to a git repository containing a directory rulebooks. This folder contains the rulebooks that are used to perform the event checks in the EDA. Rulebooks, are NOT playbooks and are treated differently here.
---
eda_projects_dev:
# - name: my_project
# description: my awesome project
# url: https://github.com/ansible/ansible-rulebook.git
# tls_validation: true
# credential: test_token
# validate_certs: false
# wait: true
# interval: 10
# sync: true
- name: webserver_checks
description: 'rulebooks for webservers'
url: https://gitlab.example.com/eda/webserver_ruleboks.git
tls_validation: true
credential: superman
sync: true
interval: 10
wait: true
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| name | "" | Yes | Str | Project name. Must be lower case containing only alphanumeric characters and underscores. |
| new_name | "" | No | Str | Setting this option will change the existing name (looked up via the name field.) |
| description | "" | No | Str | Description to use for the Project. |
| url | "" | Yes | Str | A URL to a remote archive, such as a Github Release or a build artifact stored in Artifactory and unpacks it into the project path for use. (Alias: scm_url) |
| tls_validation | True | No | Bool | Whether the URL should validate using TLS. |
| validate_certs | True | No | Bool | Whether the certificate must be validated using SSL |
| credential | "" | No | Str | The token needed to utilize the SCM URL. |
| state | present | No | str | Desired state of the project. |
rulebook_activations.yaml
EDA is all about executing rulebooks. These rulebooks include the steps that are performed to read events. And when these events are generated, they test whether they match the defined state and perform the corresponding actions.
---
eda_rulebook_activations_dev:
# - name: Github Hook
# description: Hook to listen for changes in GitHub
# project: EDA_example
# rulebook: git-hook-deploy-rules.yml
# decision_environment: Automation Hub Default Decision Environment
# extra_vars:
# provider: github-local
# repo_url: https://github.com/ansible/ansible-rulebook.git
# enabled: false
# state: present
- name: webserver check
description: check the webserver by url_check
project: webserver_checks
rulebook: check_website.yml
decision_environment: Automation Hub Default Decision Environment
enabled: true
awx_token: ...
state: present
A limitation in the configuration as code for the EDA is the content of the awx_token, which can be configured here, but it cannot be defined in the configuration as code for the controller. So there is a challenge in the event of a recovery, so it cannot be fully automated at the moment.
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| name | "" | Yes | Str | Rulebook activation name. Must be lower case containing only alphanumeric characters and underscores. |
| description | "" | No | St | Description to use for the Activation. |
| project | "" | No | St | Project to use for the Activation. |
| rulebook | "" | Yes | Str | rulebook to use for the Activation. |
| decision_environment | "" | Yes | Str | Decision_environment to use for the Activation. |
| restart_policy | "always" | No | St | Restart_policy to use for the Activation, choice of ["always", "never", "on-failure"] |
| extra_vars | "" | No | Str | Extra_vars to use for the Activation. |
| awx_token | "" | No | Str | The token used to authenticate to controller. |
| enabled | "true" | No | Str | Whether the rulebook activation is automatically enabled to run. |
| state | Present | No | Str | Desired state of the rulebook activation. |
users.yaml
# - username: jane_doe
# first_name: Jane
# last_name: Doe
# email: jdoe@example.com
# password: my_password1
# update_secrets: false
# roles:
# - Auditor
# - Contributor
# - Viewer
# - Editor
# - Operator
# - Admin
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| username | "" | yes | str | Username. Must contain only letters, numbers, and @.+-_ characters. |
| new_username | "" | no | str | Setting this option will change the existing username (looked up via the name field.) |
| first_name | "" | no | str | First ame of the user. |
| last_name | "" | no | str | Last name of the user. |
| "" | no | str | User's email address. | |
| password | "" | yes | str | Password to use for the user. |
| update_secrets | true | no | bool | Setting true will always change password if user specifies password. Password will only change if false if other fields change. |
| roles | "" | yes | list | Roles the user will have. Current acceptable values are: Viewer, Auditor, Editor, Contributor, Operator, Admin. |
| state | present | no | str | Desired state of the user. |
user_tokens.yaml
---
eda_user_tokens_dev: []
# - name: my_user_token
# description: my descioption
# token: my_token_value
Data Structure
| Variable Name | Default Value | Required | Type | Description |
|---|---|---|---|---|
| name | "" | yes | str | User Token name. Must be lower case containing only alphanumeric characters and underscores. |
| new_name | "" | no | str | Setting this option will change the existing name (looked up via the name field.) |
| description | "" | no | str | Description to use for the Project. |
| token | "" | yes | str | The value of the token to associate with the user. |
The tokens that are configured here can be created once in the automation controller and unfortunately cannot be included in the configuration as code, so in the event of a recovery, they are no longer valid and must be recreated and placed in this file. The pipeline then ensures that they become available again in EDA.