From 0f7b5e6125b21b5f36426d614ff73afa4a2bfdb0 Mon Sep 17 00:00:00 2001 From: Philippe Schmid Date: Wed, 8 Nov 2023 16:25:35 +0100 Subject: [PATCH 1/6] add nes EDA server labs as well --- content/en/docs/11/02/_index.en.md | 152 ++++++++++++++++++ content/en/docs/11/03/_index.en.md | 237 +++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 content/en/docs/11/02/_index.en.md create mode 100644 content/en/docs/11/03/_index.en.md diff --git a/content/en/docs/11/02/_index.en.md b/content/en/docs/11/02/_index.en.md new file mode 100644 index 0000000..05d5ca1 --- /dev/null +++ b/content/en/docs/11/02/_index.en.md @@ -0,0 +1,152 @@ +--- +title: 11.2. Event Driven Ansible - Events and Facts +weight: 112 +sectionnumber: 11 +--- + +In this lab we will have a closer look at events and facts. + +### Task 1 + +* Copy the rulebook from Lab 11.2 Task 3 to a new one with the name `debug_event_rulebook.yml`. +* Substitute the `run_playbook` action with a `debug` action. +* That debug action should print out all information from the event. +* Stop the httpd service on node1. +* Run the rulebook in verbose mode. The debug action should show all information about the event. + +{{% details title="Solution Task 1" %}} +```bash +cat debug_event_rulebook.yml +``` +```bash +--- +- name: show event json if site down + hosts: web + sources: + - name: check webserver + ansible.eda.url_check: + urls: + - http://:80/ + - http://:80/ + delay: 8 + rules: + - name: check if site down and debug + condition: event.url_check.status == "down" + action: + debug: + var: event +``` +```bash +ansible node1 -i inventory/hosts -b -m service -a "name=httpd state=stopped" +``` +```bash +ansible-rulebook --rulebook debug_event_rulebook.yml -i inventory/hosts -vv +``` +```bash +... +2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - call_action debug +2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - substitute_variables [{'var': 'event'}] [{'event': {'url_check': {'error_msg': "Cannot connect to host 5.102.146.223:80 ssl:default [Connect call failed ('5.102.146.223', 80)]", 'url': 'http://5.102.146.223/', 'status': 'down'}, 'meta': {'received_at': '2023-06-26T13:04:55.379428Z', 'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'uuid': '6710f9a8-c489-4699-a804-8e796855e290'}}}] +2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - action args: {'var': 'event'} +{'url_check': {'error_msg': "Cannot connect to host 5.102.146.223:80 ssl:default [Connect call failed ('5.102.146.223', 80)]", 'url': 'http://5.102.146.223/', 'status': 'down'}, 'meta': {'received_at': '2023-06-26T13:04:55.379428Z', 'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'uuid': '6710f9a8-c489-4699-a804-8e796855e290'}} +... +``` +{{% /details %}} + +### Task 2 + +* Rewrite the rulebook `debug_event_rulebook.yml`: +* Use a `run_playbook` action to start a playbook named `sos.yml` +* The playbook `sos.yml` should create an unattended sos report labeled with the fully qualified collection name of the source plugin used. Be sure to install the appropriate packages so that the sos report can be created. +* The name of the source plugin should be taken from the json output as a variable. +* The creation of the sos report takes quite some time. +* Ensure that the condition is throttled to run the action once within 5 minutes at most. +* The delay of the source check should stay at 8 seconds. +* Run the rulebook `debug_event_rulebook.yml` and ensure the sos reports on the webservers have the needed label. + + +{{% alert title="Note" color="primary" %}} +There are good onlinetools to convert [one-line json to multiline json](https://jsonformatter.curiousconcept.com) as well as [json to yaml converters](https://jsonformatter.org/json-to-yaml). Note: The json copied from the output has sometimes single quotes, RFC 8259 demands double quotes. Be sure that your converter fixes this as well. These converters can come in handy for easier reading of the output. +{{% /alert %}} + +{{% details title="Solution Task 2" %}} +See the documentation on how to [throttle event storms](https://ansible.readthedocs.io/projects/rulebook/en/stable/conditions.html#throttle-actions-to-counter-event-storms-reactive). + +```bash +cat debug_event_rulebook.yml +``` +```bash +--- +- name: run sos playbook if site down + hosts: web + sources: + - name: check webserver + ansible.eda.url_check: + urls: + - http://:80/ + - http://:80/ + delay: 8 + rules: + - name: check if site down and rebuild + condition: event.url_check.status == "down" + throttle: + once_within: 5 minutes + group_by_attributes: + - event.meta.source.type + action: + run_playbook: + name: sos.yml +``` + +```bash +cat sos.yml +``` +```bash +--- +- hosts: web + become: true + tasks: + - name: install sos package + ansible.builtin.dnf: + name: + - sos + state: installed + + - name: create a sos report unattended containing no sensitive information + ansible.builtin.command: | + "sos report --clean --batch --label {{ ansible_eda.event.meta.source.type }}" +``` + +```bash +ansible-rulebook --rulebook debug_event_rulebook.yml -i inventory/hosts -vv +``` +```bash +... +2023-06-28 11:15:53,766 - ansible_rulebook.builtin - INFO - ruleset: show event \ + json if site down, rule: check if site down and rebuild +2023-06-28 11:15:53,766 - ansible_rulebook.builtin - INFO - Calling Ansible runner + +PLAY [web] ********************************************************************* + +TASK [Gathering Facts] ********************************************************* +ok: [node1] + +TASK [install sos package] ***************************************************** +ok: [node1] + +TASK [create a sos report unattended containing no sensitive information] ****** +changed: [node1] +... +PLAY RECAP ********************************************************************* +node1 : ok=3 changed=1 unreachable=0 failed=0 +skipped=0 rescued=0 ignored=0 +2023-06-28 11:17:59,741 - ansible_rulebook.builtin - INFO - Ansible Runner \ + Queue task cancelled +2023-06-28 11:17:59,742 - ansible_rulebook.builtin - INFO - Playbook rc: 0, \ + status: successful +... +``` +{{% /details %}} + +### All done? + +* [Preview of AAP EDA-Controller GUI](https://www.youtube.com/watch?v=7i_EzHyrKQc&t=178s) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md new file mode 100644 index 0000000..b115db2 --- /dev/null +++ b/content/en/docs/11/03/_index.en.md @@ -0,0 +1,237 @@ +--- +title: 11.3. EDA-Server +weight: 113 +sectionnumber: 11 +--- + +In this lab we will learn how to use EDA-Server to run our rulebooks. Some tasks have to be done on Ascender. + +### Task 1 + +To connect your EDA-Server to your Ansible Controller, you have to create an access token on Ascender and add it to EDA-Server + +* On Ascender, create an access token for the user Ansible. Be sure to chose the write scope +* On EDA-Server add this controller token to the user Ansible + +{{% details title="Solution Task 1" %}} + +Go to the Ascender Web-GUI + +* On the left hand side, chose `Access`, then `Users` +* Click on user `ansible`, then chose the tab `Tokens` and klick on the blue butten `Add` +* Leave the `Application` field empty, add a description and chose the write scope. +* Click the `Save` button. Copy the Token from the popup window. This token is shown only once, so remember it. + +Go to the EDA-Server Web-GUI + +* On the left hand side, chose `User Access` and then `Users` +* On the right, chose user `ansible` +* Now to to the tab `Controller Tokens` +* Click on the button `Create controller token`. If you created already one, you have to delete it first to be able to create a new one. +* Enter a name, a description and paste in the token from Ascender in the `Token` field + +{% /details %}} + +### Task 2 + +Now we add a git repository with our rulebooks as a project to EDA-Server + +* Be sure, your ansible rulebooks are residing in a toplevel folder "rulebooks" inside your git repository +* Add a Project to EDA-Server pointing to your git repository + +{{% alert title="Note" color="primary" %}} +After creation the status of the project will be `failed` as long as you don't have a directory `extensions/eda/rulebooks` or `rulebooks` (relative to the root of the repository) present. +{{% /alert %}} + +{{% details title="Solution Task 2" %}} + +* On the left side navigate to `Resources` and then `Projects`. +* On the right side click on the `Create project` button. +* Enter a name, description, leave `SCM Type` as `Git`. +* As `SCM URL` enter the path to your git repository on your Controller node (https://-controller.workshop.puzzle.ch:4000/ansible/techlab). Remember to use port 4000. +* Leave the `Credential` field empty. +* Clink on `Create project` at the bottom of the page. + +{{% /details %}} + + +### Task 3 + +The last step needed to be able to run rulebooks is creating a Decision Environment. + +* Install `ansible-builder` with pip on your `-edaserver`. Be sure to install `podman` as well since it's the default container engine for `ansible-builder`. +* Prepare a yaml file `techlab-de.yml` with the definition for your Decision Environment. Take the [blueprint from the ansible-rulebook Github project](https://github.com/ansible/ansible-rulebook/blob/main/minimal-decision-environment.yml) as your base. +* Build the Decision Environment, name the image `techlab-de.yml` and tag it with `latest`. +* Push it to the container registry provided by your teacher. + +{{% details title="Solution Task 3" %}} +```bash +pip3 install -y ansible-builder podman +``` +```bash +cat techlab-de.yml +``` +``` +--- +version: 3 +images: + base_image: + name: 'registry.access.redhat.com/ubi9/python-311:latest' +dependencies: + galaxy: + collections: + - ansible.eda + python: + - azure-servicebus + - aiobotocore + - aiohttp + - aiokafka + - watchdog + - systemd-python + - dpath + - ansible-rulebook + ansible_core: + package_pip: ansible-core==2.14.4 + ansible_runner: + package_pip: ansible-runner + system: + - java-17-openjdk-devel [platform:rpm] +``` +```bash + +``` +```bash +ansible-builder build -f techlab-de.yml -t techlab-de:latest +``` +```bash +podman login https:// -u -p +podman push techlab-de:latest /techlab-de:latest +``` + +{{% /details %}} + +### Task 4 + +* Add the Decision Environment `techlab-de` you just created to EDA-Server + + +{{% details title="Solution Task 4" %}} + +* On the left side of the EDA-Server Web-GUI navigate to `Resources` then `Decision Environments`. +* On the right side, click on `Create decision environemnt`. +* Enter a name and description. +* In the `Image` field enter the path with tag to your Decision Environment (`/techlab-de:latest`) +* Leave the `Credentials` field empty +* Click on `Create decision environment` at the bottom of the page. + +{{% /details %}} + +### Task 5 + +Now have everything ready to run a ansible-rulebook. Ensure you have a job template `Provision_Webserver` in the Organization `Techlab` of your Ascender server. See the Ascender labs to set it up. + +Make the following changes to your `webserver_rulebook.yml` rulebook (Lab 11.1): + +* Change the action of the rulebook to start a job template `Provision_Webserver` in the organization `Techlab`. +* Be sure to push the changes into your git repository. +* On the EDA-Server create a `Rulebook Activation` + +{{% details title="Solution Task 5" %}} +```bash +cat webserver_rulebook.yml +``` +```yaml +--- +- name: rebuild webservers if site down + hosts: web + sources: + - name: check webserver + ansible.eda.url_check: + urls: + - http://-node1.workshop.puzzle.ch:80/ + - http://-node2.workshop.puzzle.ch:80/ + delay: 8 + rules: + - name: check if site down and rebuild + condition: event.url_check.status == "down" + action: + run_job_template: + name: Provision_Webserver + organization: Techlab +``` +* On the left side of the EDA-Server GUI, navigate to `Views`, then `Rulebook Activiations` +* On the right side click `Create rulebook activation` +* Enter the name `Webserver Provisioning`, add a description and chose the project `Techlab Repo`. +* Chose `webserver_rulebook.yml` in the `Rulebook` field. +* (if no Rulebook shows up, sync the project) +* Chose `techlab-de` in the `Decision environment` field. +* Leave `Restart policy` set to `On failure`. +* Click `Create rulebook activation` at the bottom of the page. + +{{% /details %}} + +### Task 6 + +After a successful creation of the `Rulebook Activation` you can follow its logs + +* Navigate to `Views`, then `Rulebook Activations` on the left side and then click on your `Webserver Provisioning` Rulebook Activation. +* Click on the `History` tab. +* Now click on the running instance ot the activation. +* In the `Output` field have a look at the logs + +{{% details title="Solution Task 6" %}} + +Output filed of the activation: + +```bash +2023-11-08 14:31:09,925 - ansible_rulebook.app - INFO - Starting worker mode +2023-11-08 14:31:09,925 - ansible_rulebook.websocket - INFO - websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connecting +2023-11-08 14:31:09,958 - ansible_rulebook.websocket - INFO - websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connected +2023-11-08 14:31:09,996 - ansible_rulebook.job_template_runner - INFO - Attempting to connect to Controller https://puzzle-ascender.workshop.puzzle.ch +2023-11-08 14:31:10,106 - ansible_rulebook.app - INFO - AAP Version 23.1.0 +2023-11-08 14:31:10,106 - ansible_rulebook.app - INFO - Starting sources +2023-11-08 14:31:10,107 - ansible_rulebook.app - INFO - Starting rules +2023-11-08 14:31:10,107 - ansible_rulebook.engine - INFO - run_ruleset +2023-11-08 14:31:10,109 - drools.ruleset - INFO - Using jar: /usr/local/lib/python3.9/site-packages/drools/jars/drools-ansible-rulebook-integration-runtime-1.0.5-SNAPSHOT.jar +2023-11-08 14:31:10 669 [main] INFO org.drools.ansible.rulebook.integration.api.rulesengine.AbstractRulesEvaluator - Start automatic pseudo clock with a tick every 100 milliseconds +2023-11-08 14:31:10,673 - ansible_rulebook.engine - INFO - ruleset define: {"name": "rebuild webservers if site down", "hosts": ["web"], "sources": [{"EventSource": {"name": "check webserver", "source_name": "ansible.eda.url_check", "source_args": {"urls": ["http://puzzle-node1.workshop.puzzle.ch:80/"], "delay": 8}, "source_filters": []}}], "rules": [{"Rule": {"name": "check if site down and rebuild", "condition": {"AllCondition": [{"EqualsExpression": {"lhs": {"Event": "url_check.status"}, "rhs": {"String": "down"}}}]}, "actions": [{"Action": {"action": "run_job_template", "action_args": {"name": "Provision_Webserver", "organization": "Puzzle"}}}], "enabled": true}}]} +2023-11-08 14:31:10,690 - ansible_rulebook.engine - INFO - load source +2023-11-08 14:31:11,166 - ansible_rulebook.engine - INFO - load source filters +2023-11-08 14:31:11,167 - ansible_rulebook.engine - INFO - loading eda.builtin.insert_meta_info +2023-11-08 14:31:11,586 - ansible_rulebook.engine - INFO - Calling main in ansible.eda.url_check +2023-11-08 14:31:11,587 - ansible_rulebook.websocket - INFO - feedback websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connecting +``` +{{% /details %}} + +### Task 7 + +Now, we stop the webserver on node1 and see in the logs of the rulebook activation how the rule triggers the action to start the job template on ascender and rebuild the webservers. + +{{% details title="Solution Task 7" %}} + +On -node1.workshop.puzzle.ch: +```bash +sudo systemctl stop httpd +``` + +In the logs on EDA-Server (see the last task to navigate there): +```bash +... +2023-11-08 14:33:27 847 [main] INFO org.drools.ansible.rulebook.integration.api.rulesengine.RegisterOnlyAgendaFilter - Activation of effective rule "check if site down and rebuild" with facts: {m={url_check={url=http://puzzle-node1.workshop.puzzle.ch:80/, status=down, error_msg=Cannot connect to host puzzle-node1.workshop.puzzle.ch:80 ssl:default [Connect call failed ('5.102.145.36', 80)]}, meta={source={name=check webserver, type=ansible.eda.url_check}, received_at=2023-11-08T14:33:27.845005Z, uuid=65c50f85-89af-4ab3-ac25-81a1f951c469}}} +2023-11-08 14:33:27,848 - ansible_rulebook.rule_generator - INFO - calling check if site down and rebuild +2023-11-08 14:33:40,545 - ansible_rulebook.rule_set_runner - INFO - Task action::run_job_template::rebuild webservers if site down::check if site down and rebuild finished, active actions 0 +2023-11-08 14:33:40,550 - ansible_rulebook.rule_set_runner - INFO - call_action run_job_template +2023-11-08 14:33:40,552 - ansible_rulebook.rule_set_runner - INFO - substitute_variables [{'name': 'Provision_Webserver', 'organization': 'Puzzle'}] [{'event': {'url_check': {'url': 'http://puzzle-node1.workshop.puzzle.ch:80/', 'status': 'down', 'error_msg': "Cannot connect to host puzzle-node1.workshop.puzzle.ch:80 ssl:default [Connect call failed ('5.102.145.36', 80)]"}, 'meta': {'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'received_at': '2023-11-08T14:33:27.845005Z', 'uuid': '65c50f85-89af-4ab3-ac25-81a1f951c469'}}}] +2023-11-08 14:33:40,552 - ansible_rulebook.rule_set_runner - INFO - action args: {'name': 'Provision_Webserver', 'organization': 'Puzzle'} +2023-11-08 14:33:40,552 - ansible_rulebook.action.run_job_template - INFO - running job template: Provision_Webserver, organization: Puzzle +2023-11-08 14:33:40,552 - ansible_rulebook.action.run_job_template - INFO - ruleset: rebuild webservers if site down, rule check if site down and rebuild +2023-11-08 14:34:01,225 - ansible_rulebook.rule_set_runner - INFO - Task action::run_job_template::rebuild webservers if site down::check if site down and rebuild finished, active actions 0 +``` + +Check the webpage http://-node1.workshop.puzzle.ch/ in your internet browser and ensure the page is available again. + +{{% /details %}} + +### All done? + +* From 7a5db0fb894bb4ec08c6e361ec631742953bf31f Mon Sep 17 00:00:00 2001 From: Philippe Schmid Date: Wed, 8 Nov 2023 16:31:12 +0100 Subject: [PATCH 2/6] linting --- content/en/docs/11/03/_index.en.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md index b115db2..2197139 100644 --- a/content/en/docs/11/03/_index.en.md +++ b/content/en/docs/11/03/_index.en.md @@ -48,7 +48,7 @@ After creation the status of the project will be `failed` as long as you don't h * On the left side navigate to `Resources` and then `Projects`. * On the right side click on the `Create project` button. * Enter a name, description, leave `SCM Type` as `Git`. -* As `SCM URL` enter the path to your git repository on your Controller node (https://-controller.workshop.puzzle.ch:4000/ansible/techlab). Remember to use port 4000. +* As `SCM URL` enter the path to your git repository on your Controller node (`https://-controller.workshop.puzzle.ch:4000/ansible/techlab`). Remember to use port 4000. * Leave the `Credential` field empty. * Clink on `Create project` at the bottom of the page. @@ -159,6 +159,7 @@ cat webserver_rulebook.yml name: Provision_Webserver organization: Techlab ``` + * On the left side of the EDA-Server GUI, navigate to `Views`, then `Rulebook Activiations` * On the right side click `Create rulebook activation` * Enter the name `Webserver Provisioning`, add a description and chose the project `Techlab Repo`. @@ -209,7 +210,8 @@ Now, we stop the webserver on node1 and see in the logs of the rulebook activati {{% details title="Solution Task 7" %}} -On -node1.workshop.puzzle.ch: +On `-node1.workshop.puzzle.ch`: + ```bash sudo systemctl stop httpd ``` @@ -228,10 +230,6 @@ In the logs on EDA-Server (see the last task to navigate there): 2023-11-08 14:34:01,225 - ansible_rulebook.rule_set_runner - INFO - Task action::run_job_template::rebuild webservers if site down::check if site down and rebuild finished, active actions 0 ``` -Check the webpage http://-node1.workshop.puzzle.ch/ in your internet browser and ensure the page is available again. +Check the webpage `http://-node1.workshop.puzzle.ch/` in your internet browser and ensure the page is available again. {{% /details %}} - -### All done? - -* From aa152449de70832595d7946b5b9171f14178263f Mon Sep 17 00:00:00 2001 From: Friendlypenguin Date: Wed, 8 Nov 2023 17:16:03 +0100 Subject: [PATCH 3/6] Update content/en/docs/11/03/_index.en.md Co-authored-by: Lukas Grimm --- content/en/docs/11/03/_index.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md index 2197139..2bd0bb1 100644 --- a/content/en/docs/11/03/_index.en.md +++ b/content/en/docs/11/03/_index.en.md @@ -18,7 +18,7 @@ To connect your EDA-Server to your Ansible Controller, you have to create an acc Go to the Ascender Web-GUI * On the left hand side, chose `Access`, then `Users` -* Click on user `ansible`, then chose the tab `Tokens` and klick on the blue butten `Add` +* Click on user `ansible`, then chose the tab `Tokens` and click on the blue button `Add` * Leave the `Application` field empty, add a description and chose the write scope. * Click the `Save` button. Copy the Token from the popup window. This token is shown only once, so remember it. From c01664dc80e2a63efe79014425f9eedcd5501c20 Mon Sep 17 00:00:00 2001 From: Friendlypenguin Date: Wed, 8 Nov 2023 17:16:17 +0100 Subject: [PATCH 4/6] Update content/en/docs/11/03/_index.en.md Co-authored-by: Lukas Grimm --- content/en/docs/11/03/_index.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md index 2bd0bb1..7fcbd55 100644 --- a/content/en/docs/11/03/_index.en.md +++ b/content/en/docs/11/03/_index.en.md @@ -24,7 +24,7 @@ Go to the Ascender Web-GUI Go to the EDA-Server Web-GUI -* On the left hand side, chose `User Access` and then `Users` +* On the left-hand side, chose `User Access` and then `Users` * On the right, chose user `ansible` * Now to to the tab `Controller Tokens` * Click on the button `Create controller token`. If you created already one, you have to delete it first to be able to create a new one. From 929ee96785d5bbc70e89c4bd7f4b30b75beee36e Mon Sep 17 00:00:00 2001 From: Friendlypenguin Date: Wed, 8 Nov 2023 17:16:23 +0100 Subject: [PATCH 5/6] Update content/en/docs/11/03/_index.en.md Co-authored-by: Lukas Grimm --- content/en/docs/11/03/_index.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md index 7fcbd55..379d7d4 100644 --- a/content/en/docs/11/03/_index.en.md +++ b/content/en/docs/11/03/_index.en.md @@ -26,7 +26,7 @@ Go to the EDA-Server Web-GUI * On the left-hand side, chose `User Access` and then `Users` * On the right, chose user `ansible` -* Now to to the tab `Controller Tokens` +* Now to the tab `Controller Tokens` * Click on the button `Create controller token`. If you created already one, you have to delete it first to be able to create a new one. * Enter a name, a description and paste in the token from Ascender in the `Token` field From da637e7c30ec9fdd52faafc5877e237bff09825e Mon Sep 17 00:00:00 2001 From: Friendlypenguin Date: Wed, 8 Nov 2023 17:16:31 +0100 Subject: [PATCH 6/6] Update content/en/docs/11/03/_index.en.md Co-authored-by: Lukas Grimm --- content/en/docs/11/03/_index.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/11/03/_index.en.md b/content/en/docs/11/03/_index.en.md index 379d7d4..29e40e3 100644 --- a/content/en/docs/11/03/_index.en.md +++ b/content/en/docs/11/03/_index.en.md @@ -36,7 +36,7 @@ Go to the EDA-Server Web-GUI Now we add a git repository with our rulebooks as a project to EDA-Server -* Be sure, your ansible rulebooks are residing in a toplevel folder "rulebooks" inside your git repository +* Be sure, your ansible rulebooks are residing in a top level folder "rulebooks" inside your git repository * Add a Project to EDA-Server pointing to your git repository {{% alert title="Note" color="primary" %}}