Ansible/Jinja2 asterisk conditional - ansible

Trying to update a LDAP entry via Ansible, but I want to make sure that the LDAP host wildcard ("*") is not in the host list. If I use "*" not in hosts or '*' not in hosts, Ansible does not like those. I've also tried Jinja2 search filters. Any help would be great!

The problem has nothing to do with the asterisk. It is a pure yaml syntax problem
In yaml, if you quote a variable, the representation of the value will start with a single or double quote, then you get the value itself and the closing quote. After that, the yaml parser is expecting a yank <block end>, in your specific case a new line to move on to the next value definition.
In your example, your when clause value starts with a quote. So you have to quote your entire value:
when: '"*" not in hosts'
# or
when: "'*' not in hosts"
# even
when: "\"*\" not in hosts"
A good and more readable alternative IMO is to use a yaml scalar block marker:
when: >-
"*" not in hosts

Figured this out. Was trying to do it with pipes and didn't need to.
when:
- var is not regex("\\*")

Related

How do I use a yaml anchor in an Ansible when conditional?

I'm trying to check the value of a variable in a role, but I don't know what the variable name will be beforehand, as it is set outside the role.
I tried to use a yaml anchor to achieve this like so:
- set_fact:
set_anchor: &job_status_data_key "{{ job_running_check_key }}"
[...]
- name: Set current state
set_fact:
loop_finished_successfully: true
when: *job_status_data_key != "Running"
Where job_running_check_key at the start, is set outside the role and contains the variable name I'll be checking against.
but ansible appears not to appreciate pointers in the conditionals
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: Expecting value: line 1 column 1 (char 0)
Syntax Error while loading YAML.
did not find expected key
The error appears to be in 'path/to/role/task.yml': line 15, column 30, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
loop_finished_succesfully: true
when: *job_status_data_key != "Running"
^ here
There's probably a proper syntax to achieve this, but I haven't managed to figure it out until now.
You're confusing ansible features with YAML features.
A YAML alias is a reference to an existing node. An ansible condition is a Jinja2 expression without quotes.
YAML doesn't know about ansible or Jinja. A YAML alias must be part of the YAML structure. Jinja, on the other hand, does not know about YAML. The consequences are:
*job_status_data_key != "Running"
is invalid YAML. The YAML syntax defines that an alias starts with * and contains a single name of an anchor. The following !=… content is therefore a syntax error. Now you might think „okay, let's quote it then so that YAML reads it as string and Jinja can evaluate it“:
'*job_status_data_key != "Running"'
This is now a valid YAML scalar. If given as value for when:, it will be evaluated as Jinja expression. The thing is, Jinja doesn't know that *job_status_data_key is supposed to be a YAML alias and in fact, at the time this expression is evaluated, the information about the anchored value of that name has already vanished.
The bottom line is: Don't use anchors and aliases for variables. They are a tool designed for serializing cyclic data structures inside YAML. Ansible offers variables and you should use those instead.

Multiline Template - string escaping in Ansible

I'm trying to get an effect similar to this article: https://gryzli.info/2017/12/21/ansible-debug-print-variables/
Which means in my case:
- name: Gather facts
vars:
msg: |
"{{ansible_distribution}}"
"{{ansible_distribution_major_version}}"
"{{ansible_distribution_release}}"
"{{ansible_distribution_version}}"
The problem ist that without quotes it throws an error to add the quotes. With quotes it throws the same error:
We could be wrong, but this one looks like it might be an issue with missing quotes. Always quote template expression brackets when theystart a value....
How do I correctly escape this multiline string so that Ansible can parse it? Or does this kind of code no longer work?
Q: "How do I correctly escape this multiline string so that Ansible can parse it?"
A: The problem is the indentation of the block. Quoting from Example 8.3. Invalid Block Scalar Indentation Indicators
ERROR:
A leading all-space line must not have too many spaces.
A following text line must not be less indented.
The text is less indented than the indicated level.
The correct syntax is (with or without quotation)
vars:
msg: |
"{{ansible_distribution}}"
"{{ansible_distribution_major_version}}"
"{{ansible_distribution_release}}"
"{{ansible_distribution_version}}"

Ansible: repeated lines exists but update only specific occurrence

I have to change
`<!--<parameter name=\"HostnameVerifier\">DefaultAndLocalhost</parameter>-->`
to
<!--<parameter name=\"HostnameVerifier\">AllowAll</parameter>--> in APIM_HOME/repository/conf/axis2/axis2.xml.
I am using
- name: "Modify HostnameVerifier"
lineinfile:
dest: "/home/ec2-user/ansible-test/wso2am-2.0.0/repository/conf/axis2/axis2.xml"
state: "present"
line: "\t\t<parameter name=\"HostnameVerifier\">AllowAll</parameter>"
regexp: "<!--<parameter name=\"HostnameVerifier\">DefaultAndLocalhost</parameter>-->"
This is only replacing the 3rd occurrence of the regexp. I want it to replace only 2nd occurrence. How do I do that?
You can't do this with lineinfile. From the docs:
...only the last line found will be replaced...
And lineinfile iterates line-by-line – you can't add more context to it.
You should use replace module and add more context to the regexp to match exatly that part of file you want to modify. You can use multiline patterns here.

Using ansible lineinefile with colon in line

I am trying to make sure that a particular line is commented out in a source file.
The line is like this:
CFUNCTYPE(c_int)(lambda: None)
If it exists, I want to comment it out:
# CFUNCTYPE(c_int)(lambda: None)
If it doesn't exist, just ignore it.
If it exists and is already commented out, do nothing.
This is the playbook I wrote, but it doesn't work.
tasks:
- name: fix ctypes file
lineinfile: dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp="^#?CFUNCTYPE(c_int)(lambda: None)" line='# CFUNCTYPE(c_int)(lambda: None)'
The error says:
This one looks easy to fix. There seems to be an extra unquoted colon in the line
and this is confusing the parser. It was only expecting to find one free
colon. The solution is just add some quotes around the colon, or quote the
entire line after the first colon.
However, it is not easy to fix, and I've tried quoting it in every way I can think of, to no avail.
It's a YAML limitation; the parser likely wants to either see a name, colon, and name=value pairs with no more colons on the line, or just name, colon, and 1 quoted string value.
The lineinfile doc has an example for sudoers mentioning this (and another one further down that doesn't work...) and it references YAML as the problem. This means any time you need to have a colon in a value you may as well quote the entire string of arguments just to save yourself the debugging hassle.
I made it work with this quoting:
lineinfile: "dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp='^#?CFUNCTYPE(c_int)(lambda: None)' line='# CFUNCTYPE(c_int)(lambda: None)'"
In order to ignore a file that doesn't exist, I used this code:
- stat: path=/usr/local/lib/python2.7/ctypes/__init__.py
register: init
- name: fix ctypes file
replace: "dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp='^( CFUNCTYPE.c_int..lambda: None.)' replace=' # CFUNCTYPE(c_int)(lambda: None)'"
when: init.stat.exists == True
sudo: yes
I also had to change lineinfile to replace, because the line is prefixed with 4 spaces, and I couldn't get it to match correctly.

Remove a line from a file using ansible?

I have a file called authorized_keys. I need to delete a particular line using an Ansible script.
The problem is when I try to remove a line that includes a '+' character. Ansible is not able to remove this line.
e.g authorized_keys file is:
.....
abhi foo+bar saken
......(EOF)
I want to remove the abhi foo+bar saken line but Ansible is not removing this line because of the + character.
I am able to remove lines that do not contain a + character .
Task:
- name: Delete keys in sysadmin/.ssh/authoriezd_keys
lineinfile: dest=/home/{{name}}/.ssh/authorized_keys
state=absent
regexp='^{{key}}$'
PS: I am using Ansible's lineinfile module
The problem probably is that + has a meaning in a regular expression.
You should be able to fix it by escaping the +. If you can't do that from the source where {{ key }} is defined, you can escape it with the replace Jinja filter:
- name: Delete keys in sysadmin/.ssh/authoriezd_keys
lineinfile: dest=/home/{{name}}/.ssh/authorized_keys
state=absent
regexp='^{{ key | replace("+", "\+") }}$'
You might run into more problems if {{ key }} contains other characters which have a meaning in regular expressions. If that's the case I think the safe way would be to create your own filter plugin where you simply return the input passed through re.escape.

Resources