Run ansible via command line using with_items - ansible

I have item list of IPs:
server_hosts:
- { host: '1.1.1.1' }
- { host: '10.10.10.10' }
I want to pass only one of the items in the command line:
ansible-playbook base.yml -i ${host}, --extra-vars "env_name=lab server_hosts={host:'${1.1.1.1}'} "
but this gives an error of:
{"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'unicode' object has no attribute 'host'\n\nThe error
Any advice how to pass a specific item from list in the command line?

Please pay attention to a side note here:
Note: Values passed in using the key=value syntax are interpreted as strings. Use the JSON format if you need to pass in anything that shouldn’t be a string (Booleans, integers, floats, lists etc).
So, you should use:
--extra-vars '{"env_name":"lab","server_hosts":{"host":"1.1.1.1"}}'
Otherwise you end up with server_hosts as string, not an object.

Related

How to render a literal 'null' in Jinja2 Template

I'm working on an ansible role that allow users to interact with a REST API. I create json.j2 templates that allow me to build the message payload and eventually submit. One of the fields expects either a string value ("") or null.
{
"value": "{{ example.value | default(null, true) }}"
}
This doesn't work and I get this error:
The task includes an option with an undefined variable. The error was: 'null' is undefined
I need that null value and I need to come in as the default value if no other value is provided.
How do I do this?
As pointed in the comments, null has no meaning in Python, None is the Python representation of what your are looking for.
Now, if you want to convert this to a JSON value, then there is a to_json filter in Ansible, so:
'{ "value": {{ example.value | default(None, true) | to_json }} }'
Would end up as:
{ "value": null }

Jinja2 - create a dynamic variable using value of variable as part of the key of another variable

I am writing a jinja2 template for an Ansible role. I have this in my role/x/vars/main.yml
switches:
- hostname: foo
customer: abc
abc_secret_key: myP#$$word
xyz_secret_key: myS3cr3t
In my template, I want to reference the secret key based on the value of customer variable.
I can reference abc_secret_key by using {{ item.abc_secret_key }}. That works, no problem. However I really want to build the variable name dynamically and use the value of the "customer" variable (in the case abc) as part of variable name abc_secret_key.
This does not work.
I get
"msg": "AnsibleUndefinedVariable: 'dict object' has no attribute u'abc'"
but, hopefully it illustrates what I am trying to do
my secret key is {{ item[item.customer]['_secret_key'] }}
I would like it to render like this:
my secret key is myP#$$word
I have tried about 10-15 different renditions but, can not pin down the right syntax.
As you see the dict key lookup with a literal string key, you can compose a dynamic string to serve as the dict key:
- debug:
msg: my secret key is {{ item[ item.customer ~ '_secret_key'] }}
Where the ~ is jinja2 syntax for string concatenation where either side is first coerced to a string, and then concatenated. You are welcome to use +, too, if you are certain that both sides are already strings (as is likely the case here, base on your cited example):
- debug:
msg: my secret key is {{ item[ item.customer + '_secret_key'] }}

Pass variable inside nested jinja template in Airflow

I created a Variable (from Airflow UI):
Key: env_variables
Value: {'xx': 'yy`}
and trying to access using var.json.env_variables.xx inside bash operator. But the value of "xx" is dynamic, which
I am passing from REST API and accessing it using dag_run.conf['param'] (dag_run.conf['param'] should return xx). Eventually I want to run var.json.env_variables.xx. How can I achieve that inside bash operator in Airflow?
I am trying to run the following code but its showing Jinja Syntax Error.
task = BashOperator(
bash_command="export KUBECONFIG=$KUBECONFIG:{{var.json.env_variables.{{dag_run.conf['param']}} }}
What I want:
It should fetch the value of var.json.env_variables.xx. I have also tried using params but no luck, params.path is returning None.
task = BashOperator(
bash_command="export KUBECONFIG=$KUBECONFIG:{{params.path}},
params: {
"path":env_variables.get('{{dag_run.conf["param"]}}')
}
Any kind of help is highly appreciated.
You don't need the extra {{...}} in the Jinja expression around dag_run.conf and you'll also need the typical item access of a dictionary. Try using a template expression like this:
nested_vars = BashOperator(
task_id="nest_vars",
bash_command="export KUBECONFIG=$KUBECONFIG:{{ var.json.env_variables[dag_run.conf['param']] }}"
)
This is the log entry when passing in a triggering config of {"param": "xx"} to the operator instantiation above:
INFO - Running command: ['bash', '-c', 'export KUBECONFIG=$KUBECONFIG:yy']

Passing sub vars to Ansible command line

I have an ansible playbook that gets its vars passed in from an extra-vars.json file. It gets passed in at the command line with --extra-vars "#extra-vars.json".
This is an abbreviated version of the var file
{
"source" : {
"access_token" : "abc",
"git_instance_url" : "foo.com",
"repo" : "some-group/some-project/some-repo"
},
"target" : {
"access_token" : "xyz",
"git_instance_url" : "foo.bar.com",
"repo_path" : "lorem/ipsum"
}
}
Because of the var structure, when I call the vars in my playbook I have to use dot notation i.e. {{ source.repo_path }} or {{ target.access_token }}. My problem is that I would like to remove a couple of these vars from the extra-vars.json and pass them individually at the command line. If I remove source.git_instance_url from extra-vars.json I can pass it in without any precedence conflicts.
My issue is that I can't figure out how to pass dot notation vars in at the command line. I don't want to change my playbook to do this. If I pass in --extra-vars "source.git_instance_url=bar.baz.com" I get an error source is undefined.
I tried using bracket notation source[git_instance_url]=bar.baz.com with no success.
Is there a way to pass dot notation vars at the command line or am I going to have to change my playbook from {{ source.git_instance_url }} ==> {{ source_git_instance_url }} to be able to accomplish this?
When passing extra vars, these are always "string variables". I learned it the hard way when trying to pass in boolean variables.
You could pass them as json:
ansible-playbook -e '{"source": { "git_instance_url": "foo" }}' playbook.yml
But I don't know right now, if they get merged with the source var from your vars file. I'd guess, one overwrites the other. So you probably end up with either the source var from your string or with the one from the file.

How do I check if variable defined in an Ansible playbook contains a string value?

I want to validate that the input values passed to the variables as extra_args.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
The values are passed to them as extra_args when executing the playbook.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
This task fails if the variable is not a string object:
- fail:
when: variable is not string
But be aware that all values passed as extra-vars will be strings, because that's what they are -- anything you type on your keyboard is a valid string. As there is no type declaration, even if a variable contains a numerical value, it will be stored in a string object.
It is different to variable values defined in YAML which undergo type autodetection performed by YAML parser. For example if you type myvar: true in YAML, it will be considered Boolean object true, but if you pass the same value with --extra-vars "myvar:true", it will be a string object true.
You need to specify another condition.
Here are few filters and tests in ansible you may find it useful
http://docs.ansible.com/ansible/latest/playbooks_filters.html
http://docs.ansible.com/ansible/latest/playbooks_tests.html
for validation you might use it as follows:
tasks:
- fail: msg="Variable '{{ item }}' is not a string"
when: string | search("^[a-zA-Z]*$")
I prefer to use the 'assert' module for such cases like this.
- name: Test if the type of 'variable' is string
assert:
that:
- variable is defined
- variable is string
fail_msg: |
variable: {{ variable | d() | to_nice_json }}
seealso: type check examples: https://github.com/ssato/ansible-role-assertive-programming-examples/blob/master/tasks/pre_type_checks.yml
BTW, if you want to define variables with types you want using --extra-vars (-e) option, you need to prepare yaml files define these variables and let them loaded using '#' such like '-e #/path/to/the/yaml_file'.

Resources