Variable Precedence and Working With Facts
Goal
You separate values from the code, place them in several locations, and check for yourself which one wins. You also handle values obtained during the run through facts and register.
Why it matters
The answer to the question "I changed the variable but it doesn't take effect" is almost always precedence. Ansible accepts variables of the same name in several places, and even when they conflict, it raises no error and quietly uses the stronger one. This property is convenient but makes debugging hard. So you need a design sense of putting values that may be overridden in a weak place (a role's defaults) and values that must be kept in a strong place. Command-line -e beats everything but is recorded nowhere, so if you used it during incident response, you must bring it back into the code. Otherwise the next deployment quietly wipes that value out.
Steps
- Create
/root/ans/vars/site.ymland, in the play'svars:, defineapp_name: checkout. Write that value to/root/ans/vars/out/app_name.txt. - In
/root/ans/vars/vars/common.yml, putapp_port: 9090and load it withvars_files. Write the value to/root/ans/vars/out/app_port.txt. - In
/root/ans/inventory/group_vars/web.ymlputnode_role: frontend, and in/root/ans/inventory/host_vars/web1.ymlputnode_role: canary. The two directories must be in the same place as the/root/ans/inventory/hosts.iniyou made in the first lab to be read automatically. It must show as frontend on web2 and as canary on web1. - Run a command, receive the result with
register, and then save only the standard output to/root/ans/vars/out/uptime.txt. - Turn on
gather_factsand save JSON containing the host name, architecture, and system from the collected facts to/root/ans/vars/out/facts.json. - Run with
-e app_port=9999and save that value to/root/ans/vars/out/precedence.txt. Theapp_port.txtyou made in step 2 must still be 9090. - Use
set_factto build a value that joinsapp_nameandapp_port, and save it to/root/ans/vars/out/endpoint.txtin the formcheckout:9090. - Create
/root/ans/vars/out/summary.json. It must have four keys:app(=checkout),port(=9090),role(the value of web1's host variable), andhost(the host name from the collected facts).
Notes
- A lab Pod is created fresh for each lab. If
/root/ans/inventory/hosts.inidoes not exist, first recreate the same inventory you made in the first lab (web1, web2, db1,ansible_host=127.0.0.1,ansible_port=2222,ansible_user=root, web and db under[prod:children]). For the structure, refer to/opt/lab/fixtures/ansible/inventory.sample.ini. - With
ansible-inventory -i /root/ans/inventory/hosts.ini --listyou can see how the group and host variables were actually merged. - With the
debugmodule'svar:you can immediately check the final value of a particular variable. - Common mistake 1: writing the entire register object to a file in step 4. You need only
.stdout. - Common mistake 2: overwriting the same file in step 6 and losing the earlier result. Leave each step's result in a different file.
Define and use a play variable
Create /root/ans/vars/site.yml and, in the play's vars:, define app_name: checkout. Write that value to /root/ans/vars/out/app_name.txt.
Put the value under the play's vars: and reference it with Jinja2 in the content of the copy module.
Split out a variable file
In /root/ans/vars/vars/common.yml, put app_port: 9090 and load it with vars_files. Write the value to /root/ans/vars/out/app_port.txt.
vars_files: is a list of paths. As values grow in number, it is customary to detach them from the play.
Create group variables and host variables
In /root/ans/inventory/group_vars/web.yml put node_role: frontend, and in /root/ans/inventory/host_vars/web1.yml put node_role: canary. The two directories must be in the same place as the /root/ans/inventory/hosts.ini you made in the first lab to be read automatically. It must show as frontend on web2 and as canary on web1.
The directory name is the rule. The file name under group_vars is the group name, and under host_vars it is the host name.
Store a command result in a variable
Run a command, receive the result with register, and then save only the standard output to /root/ans/vars/out/uptime.txt.
What you receive with register is an object. Put only its standard output in the file.
Collect facts and save them as JSON
Turn on gather_facts and save JSON containing the host name, architecture, and system from the collected facts to /root/ans/vars/out/facts.json.
Turn on gather_facts, pick part of ansible_facts, and write it as JSON. The to_nice_json filter helps.
Override with a command-line variable
Run with -e app_port=9999 and save that value to /root/ans/vars/out/precedence.txt. The app_port.txt you made in step 2 must still be 9090.
The value passed with -e is the strongest. Do not overwrite the file you saved in the earlier step; leave it under a different name.
Combine values with set_fact
Use set_fact to build a value that joins app_name and app_port, and save it to /root/ans/vars/out/endpoint.txt in the form checkout:9090.
Build a new value that joins the two variables and write it to the file. The format is 이름:포트 (name, a colon, then port).
Build a summary combining variables, facts, and host variables
Create /root/ans/vars/out/summary.json. It must have four keys: app (=checkout), port (=9090), role (the value of web1's host variable), and host (the host name from the collected facts).
Build JSON with four keys (app, port, role, host). role comes from web1's host variable, and host comes from the collected facts.