The Wizard: Scenarios- 8 mins
You just don’t know how to do it.
You’ve been thinking about it for a while too. It’s an important issue. The crafting of the spell is the most important part. The journey is usually more important than the destination itself. But you don’t feel like you are doing it right.
The purpose is simple, yet it has a duality of character. You want to enable the transmission of information between all realms into a single library of knowledge. A task you’ve already accomplished many times in the past.
--- # filebeat/tasks/main.yml - name: install Filebeat package: name: filebeat= state: present update_cache: true notify: restart Filebeat - name: copy configuration file template: src: filebeat.yml.j2 dest: /etc/filebeat/filebeat.yml owner: root group: root mode: 0600 notify: restart Filebeat - name: start Filebeat service: name: filebeat state: started enabled: true
You have crafted this spell properly, following the same principles you have taught many people across the years, the same ones you’ve used for your own. The same ones that Merlin taught you the first time he showed you how to create a playground to refine your creations, thousand of years ago.
import os import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') def test_filebeat_is_installed(host): filebeat = host.package('filebeat') assert filebeat.is_installed def test_filebeat_is_running(host): filebeat = host.service('filebeat') assert filebeat.is_running def test_filebeat_is_enabled(host): filebeat = host.service('filebeat') assert filebeat.is_enabled def test_filebeat_configuration_exists(host): filebeat = host.file('/etc/filebeat/filebeat.yml') assert filebeat.exists
Nevertheless, you want to add an extension to the spell, depending on whether you want to receive information about all the portals you’ve spawned into this world or not. Visualisation is key.
--- # filebeat/tasks/main.yml ... - name: include module tasks import_tasks: nginx_module.yml when: activate_filebeat_nginx_module --- # filebeat/tasks/nginx_module.yml - name: copy nginx module file template: src: nginx.yml.j2 dest: /etc/filebeat/modules.d/nginx.yml owner: root group: root mode: 0644 register: nginx_module notify: restart Filebeat - name: setup filebeat shell: filebeat setup -e && touch /tmp/filebeat_configured when: nginx_module.changed tags: - skip_ansible_lint
You know how to craft the general part of the spell, but not the extension. If only…
N appears out of thin air.
- Hey! What are you up to?
- Fighting with an Ansible role.
- Can I help?
- Sure. I’m trying to conditionally add some tasks to my role, but only if I want the nginx logs to be forwarded to my Elasticsearch cluster. I use the nginx Filebeat module, which also happens to create pretty cool dashboards.
- Great. Just use an include_tasks conditioned by a boolean variable defined somewhere. You could name it
activate_filebeat_nginx_module, for example.
- Yeah, that’s what I did. Then again, my problem isn’t that part, but rather testing the conditional part. I don’t activate the module by default. The
activate_filebeat_nginx_moduleis set to false in the role’s defaults. So my Molecule test only tests the default case.
- Yes. That’s because that’s the default scenario. Just create another scenario.
N pulls up his sleeves and steps forward.
- Remember how you taught me how to create a role with tests using Molecule? The principle is rather simple. You type
molecule init role --role-name filebeatand Molecule creates all the resources you’re going to need in order to test your role. That includes the test files and all the other playbooks you may need: the prepare playbook, the side_effects playbook…
- Indeed. I remember.
- The thing is that Molecule creates a
defaultscenario in order to do that. That’s why all your resources are under the
molecule/defaultdirectory on your role.
N waves his hands around in the air. Light appears everywhere, and you can see the structure of your current spell:
filebeat/ ├── README.md ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── molecule │ └── default └── tasks ├── main.yml └── nginx_module.yml
- You’re right.
- If you examine the playbook on the default directory, you will see that there are no variables specified for the role.
N waves his hands once again in the air and the light and the images change:
--- # filebeat/molecule/default/playbook.yml - name: Converge hosts: all roles: - role: filebeat
- This is because you are actually testing the
defaultscenario: the one where you only use the default variables that are defined in the
defaultdirectory of your role.
- I see.
You have seen this before, but you’ve never really understood the abstractions or their meaning, even if you’ve already been doing this for a while. You feel on the verge of enlightenment.
- So you just need to create a new scenario.
N claps his hands, and energy starts flowing through him as a new component of the enclosure you used in order to craft your test appears.
molecule init scenario --scenario-name activate_filebeat_nginx_module --role-name filebeat --> Initializing new scenario activate_filebeat_nginx_module... Initialized scenario in filebeat/molecule/activate_filebeat_nginx_module successfully. molecule ├── activate_filebeat_nginx_module │ ├── Dockerfile.j2 │ ├── INSTALL.rst │ ├── create.yml │ ├── destroy.yml │ ├── molecule.yml │ ├── playbook.yml │ ├── prepare.yml │ └── tests └── default ├── Dockerfile.j2 ├── INSTALL.rst ├── create.yml ├── destroy.yml ├── molecule.yml ├── playbook.yml ├── prepare.yml └── tests
You both walk to the new part of the playground.
- In this new directory, you can specify everything you need in order to properly test your new scenario. What do you need first?
- I need to specify that I want to include the conditional part of my playbook.
- Where would you do that?
- I’d use the group_vars at the playbook level.
- That’s good. Then again, there are no group_vars here. You only have a small playbook that specifies everything you do in order to test your role.
- So I’ll do it in the playbook.yml file.
- Isn’t that a bit dirty? I’ve always thought that you’re not supposed to use variables on a playbook, but rather put them somewhere else.
- That’s a style thing, but yes, I would say that generally it is a good practice. Nevertheless, it is precisely what you need right now. As I just said, your playbook defines every parameter used to test your role. It’s easy to see how are you testing your role just by looking at it. You know precisely which variables are defined and how. Even if the name of the scenario should be explicit enough already in order to understand it. Try it.
You mold the spell accordingly.
--- # filebeat/molecule/activate_filebeat_nginx_module/playbook.yml - name: Converge hosts: all roles: - role: filebeat activate_filebeat_nginx_module: true
- Good. Now you can test everything you wanted. Just remember that in order to test every scenario, you need to use
molecule test --all. This will execute every scenario, which is probably what you want. If you want to speed up the red/green/refactor loop, you can use the
verifyactions like you taught me before, but you need to specify the scenario name when executing every action, like this:
molecule create --scenario-name activate_filebeat_nginx_module
You are impressed with N. It’s hard to believe that you were the one teaching him things once. Maybe he’s been the one teaching you all from the start.
- That’s precisely what I needed.
- I’m glad I could be of service. Do you need any more help?
- No, I’m all set. I just…
You’re having a déjà-vu. N is outside your field of vision. You slowly turn your head around…
N is still there.