How $ works in Ansible list - regex

I'm new in ansible so I've been learning about how it works. And while I was doing so, I'm stumped in the RegEx because it doesn't work for some reason. Here's the code i'm working on.
---
- hosts: localhost
#get the targeted file
vars:
contents: "{{lookup ('file', '/home/sample/test.txt')}}"
tasks:
- name: Replacing strings
include_role:
name: ansible-replace-string
And then this the code for the role
- name: Removing the suffix .ear and ear
debug:
msg: "{{contents | map('regex_replace', '\\.ear', '') | list}}"
msg: "{{contents | map('regex_replace', 'ear$', '') | list}}"
I've read that $ is used if you want to capture particular string at the end. So I'm trying to capture .ear and ear. While .ear works fine, if I try and put the ear$ it breaks my code. If I remove the first msg, ear$ only works if there's no dot before it. For example:
byedear -> byed
web.statements.dear -> web.statements.dear
I'm not sure as to why it doesn't work for the second example. If needed further content here's a snippet of the test.txt i'm trying to play around with.
web.appstatementear
web.statements.ear
web.payments.ear
TmStatearments
hellodear
byedear
If anyone has ideas I'd be happy to hear them!

Related

Looking to see if a key from one set of imported variables matches another so it's value can be procured

I have roughly formatted yml files with key/value pairs in them. I then imported the values of both of these files successfully into a running playbook using the include_vars module.
Now, I want to be able to compare the value of the key/value pair from file/list 1, to all of the keys of file/list 2. Then finally when there is a match, print and preferably save/register the value of the matching key from file/list 2.
Essentially I am comparing a machine name to an IP list to try to grab the IP the machine needs out of that list. The name is "dynamic" and is different each time the playbook is run, as file/list 1 is always dynamically populated on each run.
Examples:
file/list 1 contents
machine_serial: m60
s_iteration: a
site_name: dud
t_number: '001'
file/list 2 contents
m51: 10.2.5.201
m52: 10.2.5.202
m53: 10.2.5.203
m54: 10.2.5.204
m55: 10.2.5.205
m56: 10.2.5.206
m57: 10.2.5.207
m58: 10.2.5.208
m59: 10.2.5.209
m60: 10.2.5.210
m61: 10.2.5.211
In a nutshell, I want to be able to get the file/list 1 ct_machine_serial key who's value is currently: m60 to be able to find it's key match in file/list 2, and then print and/or preferably register it's value of 10.2.5.210.
What I've tried so far:
Playbook:
- name: IP gleaning comparison.
hosts: localhost
remote_user: ansible
become: yes
become_method: sudo
vars:
ansible_ssh_pipelining: yes
tasks:
- name: Try to do a variable import of the file1 file.
include_vars:
file: ~/active_ct-scanner-vars.yml
name: ctfile1_vars
become: no
- name: Try to do an import of file2 file for lookup comparison to get an IP match.
include_vars:
file: ~/machine-ip-conversion.yml
name: ip_vars
become: no
- name: Best, but failing attempt to get the value of the match-up IP.
debug:
msg: "{{ item }}"
when: ctfile1_vars.machine_serial == ip_vars
with_items:
- "{{ ip_vars }}"
Every task except the final one works perfectly.
My failed output final task:
TASK [Best, but failing attempt to get the value of the match-up IP.] ***********************************************************************************
skipping: [localhost] => (item={'m51': '10.200.5.201', 'm52': '10.200.5.202', 'm53': '10.200.5.203', 'm54': '10.200.5.204', 'm55': '10.200.5.205', 'm56': '10.200.5.206', 'm57': '10.200.5.207', 'm58': '10.200.5.208', 'm59': '10.200.5.209', 'm60': '10.200.5.210', 'm61': '10.200.5.211'})
skipping: [localhost]
What I hoped for hasn't happened, it simply skips the task, and doesn't iterate over the list like I was hoping, so there must be a problem somewhere. Hopefully there is an easy solution to this I just missed. What could be the correct answer?
Given the files
shell> cat active_ct-scanner-vars.yml
machine_serial: m60
s_iteration: a
site_name: dud
t_number: '001'
shell> cat machine-ip-conversion.yml
m58: 10.2.5.208
m59: 10.2.5.209
m60: 10.2.5.210
m61: 10.2.5.211
Read the files
- include_vars:
file: active_ct-scanner-vars.yml
name: ctfile1_vars
- include_vars:
file: machine-ip-conversion.yml
name: ip_vars
Q: "Compare the machine name to an IP list and grab the IP."
A: Both variables ip_vars and ctfile1_vars are dictionaries. Use ctfile1_vars.machine_serial as index in ip_vars
match_up_IP: "{{ ip_vars[ctfile1_vars.machine_serial] }}"
gives
match_up_IP: 10.2.5.210
Example of a complete playbook for testing
- hosts: localhost
gather_facts: false
vars:
match_up_IP: "{{ ip_vars[ctfile1_vars.machine_serial] }}"
tasks:
- include_vars:
file: active_ct-scanner-vars.yml
name: ctfile1_vars
- include_vars:
file: machine-ip-conversion.yml
name: ip_vars
- debug:
var: match_up_IP

Ansible regex_search stdout not working, but works in regex101.com

I've read a thousand of the Ansible regex_search questions on here and have not found a satisfying answer.
Here's the test playbook. backup_stdout is set identically to what I get from the backup utility:
---
- hosts: localhost
connection: local
gather_facts: no
vars:
backup_stdout: |-
Saving active configuration...
/var/local/ucs/f5-apm-1625-081021.ucs is saved.
tasks:
- name: Get the backup name
ansible.builtin.set_fact:
backup_name: "{{ backup_stdout | regex_search(stdout_regex, multiline=True) }}"
vars:
stdout_regex: '"\/var.*ucs\b"gm'
failed_when: backup_name == ''
- debug:
var: backup_name
I can't get the regex_search to produce a match. Here's the same code on regex101, which shows that it does match. I've tried the following:
with/without the multiline
with/without the trailing '\\1' in the expression
with/without passing the result to the | first filter
using ^\/var.*ucs instead of the word boundary (also matches on regex101)
So far, no matter what I've tried, I can't get the Ansible to match. Any help appreciated.
You've got some weird quoting in your regular expression that is causing problems. Because you've written:
stdout_regex: '"\/var.*ucs\b"gm'
You're passing the literal value "\/var.*ucs\b"gm to regex_search. There are no quotes (nor is there a gm) in the content of backup_stdout, so this is never going to match.
I think you want:
- hosts: localhost
connection: local
gather_facts: no
vars:
backup_stdout: |-
Saving active configuration...
/var/local/ucs/f5-apm-1625-081021.ucs is saved.
tasks:
- name: Get the backup name
ansible.builtin.set_fact:
backup_name: "{{ backup_stdout | regex_search(stdout_regex, multiline=True) }}"
vars:
stdout_regex: '/var.*ucs\b'
failed_when: backup_name == ''
- debug:
var: backup_name
Which produces:
TASK [debug] *******************************************************************
ok: [localhost] => {
"backup_name": "/var/local/ucs/f5-apm-1625-081021.ucs"
}

ansible playbook : Error to connect to a windows host (winrm) using aws secret manager

i try to connect my ansible host to a windows server using winrm
my ansible version :
ansible 2.10.8
config file = None
configured module search path = ['/home/ec2-user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ec2-user/.local/lib/python3.6/site-packages/ansible
executable location = /home/ec2-user/.local/bin/ansible
python version = 3.6.8 (default, Dec 5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
it work when the password is in vars
- hosts: win
vars:
ansible_user: "ansible"
ansible_password: "Itismypassword"
and it is not working with this configuration :
- hosts: win
vars:
ansible_user: "ansible"
ansible_password: "{{ lookup('amazon.aws.aws_secret', 'ansible_password', bypath=true) | regex_search ('ansible_password\\\":\\\"(.*)\\\"','\\1')}}"
i retrieve the password ( i used a regex to get only the password, i'm not sure that is the correct way to do that)
when i want to use it i get this error:
fatal: [win_server]: FAILED! => {
"msg": "Invalid type for configuration option plugin_type: connection plugin: winrm setting: remote_password : Invalid type provided for \"string\": ['Itismypassword']"
}
thanks for your help !
The error message is pretty clear: list[str] != str; while I don't have an AWS Secret Manager to test against, thankfully the error message makes knowing the fix pretty obvious: grab the | first of the resulting list
ansible_password: "{{
lookup('amazon.aws.aws_secret', 'ansible_password', bypath=true)
| regex_search ('ansible_password\\\":\\\"(.*)\\\"','\\1')
| first }}"
As for your aside, the answer is for sure not to use regex to extract those values; based on the regex you're using, I'm guessing the output of that aws_secret lookup is in fact JSON, and thus the correct behavior is to | from_json to turn it back into a dict (or list[dict]), then extract the key you want
something like this, but without knowing the actual shape this is likely not 100% correct:
ansible_password: >-
{{ lookup('amazon.aws.aws_secret', 'ansible_password', bypath=true)
| from_json | map(attribute='ansible_password') | first }}
thanks to mdaniel i progress in my understanding of ansible and aws secret manager: it's working with regex but i try to figure out how to do it in a proper way...
when i get secret from aws secret manager with this commands :
debug: msg="{{ lookup('amazon.aws.aws_secret', 'ansible_secret', bypath=true) | dict2items }} "
i have this answer :
"msg": [
{
"key": "ansible_secret",
"value": "{\"password\":\"itismypassword\",\"user\":\"ansible_user\"}"
}
]
i don't know how to get "itismypassword" from value field >< a jquery maybe ?

Replace Specific String in YAML File using Ansible

I have a web application that uses a YAML file for configuration. This is an except from the file:
---
settings:
domain: 127.0.0.1
I have an Ansible playbook that uses the lineinfile module to replace the IP address in the YAML file above with the server's public IP address.
- name: Discovering Public Internet Protocol Address
ipify_facts:
register: public_ip
- name: Configuring Application with discovered Public IP
lineinfile:
dest: /application/path/settings.yml
regexp: '^(.*)domain: (.*)$'
line: 'domain: {{ ipify_public_ip }}'
This finds and replaces the 127.0.0.1 IP with the public server's IP but it breaks the YAML indentation as follows:
---
settings:
domain: 54.12.33.3
Problem: "domain" is moved to the same line with "settings" and my ruby app fails to run migrations because it identifies a YAML syntax error.
I do not mind replacing lineinfile with another module, but I'd like to keep it if possible. I've been struggling with this for hours and will appreciate any assistance.
As a quick solution, try to use the 2 spaces () for a better match and substitution:
regexp: '^.*domain: (.*)$'
line: ' domain: {{ ipify_public_ip }}'
I'm sure other improvements can be made to the regex, to use \s or [:space:].
UPDATE: .* from the beginning of regexp shouldn't be needed. Updated per comment requested.
You could just create a yaml template verision.
- template:
src: /path/to/settings.tpl.yml
dest: /path/to/settings.yml
settings.tpl.yml
---
settings:
domain: {{ public_ip }}

Ansible regex_replace filter does not work

I try to use Ansible regex_replace to filter the sub-string "application_1514971620021_4505" from a status message.
In the shell the message looks like this:
I run this code in Ansible:
---
- hosts: [npif]
remote_user: root
tasks:
- block:
- name: Admin submit check
command: chdir=/usr/spring-xd-1.3.1.RELEASE-yarn/ bin/xd-yarn submitted
register: admininfo
- debug: msg="{{ admininfo.stdout }}"
- debug: msg="{{ admininfo.stdout | regex_replace('^.*(application\_\d.*\_\d*)\s.*', '\\1') }}"
become: yes
become_user: ingestdev
debug: msg="{{ admininfo.stdout }}" returns the status message in the different format than in the shell:
ok: [npif] => {
"msg": " APPLICATION ID USER NAME QUEUE TYPE STARTTIME FINISHTIME STATE FINALSTATUS ORIGINAL TRACKING URL\n ------------------------------ --------- --------- -------- ---- -------------- ---------- ------- ----------- ------------------------\n application_1514971620021_4505 ingestdev spring-xd batch_cb XD 1/3/18 2:49 PM N/A RUNNING UNDEFINED http://x.x.x.x:9394"
}
When I run the second debug with regex_replace, I get the identical output to the first debug output - no regex_replace filter has been applied. The regex filter is correct - I've tested it externally. Basically the Ansible code is working too - I have tested with line below and got "test" as expected.
- debug: msg="{{ 'test.home.com' | regex_replace('^([^.]*).*', '\\1') }}"
Do you have an idea, what is wrong with my approach?
Your first problem is that .* doesn't appear to match newlines. Consider this:
- debug:
msg: "{{ admininfo.stdout | regex_replace('.*application', 'foo') }}"
This will replace application with foo, but will leave the header lines intact. Since the ^ anchors your regular expression to the beginning of the text (not the beginning of a line) your expression will never match.
You can take advantage of the fact that ansible has already provided you with individual lines in the stdout_lines key of your registered output. In this case, you would use something like:
- debug:
msg: >
{{ admininfo.stdout_lines[2] | regex_replace('^.*(application_\d.*_\d*)\s.*', '\1') }}
Note here that I've made a few changes in how things are quoted and escaped. In particular, I'm using the folded literal operator > in place of double quotes, and you neede to use \1 instead of \\1 for your replacement string.
This gives me:
ok: [localhost] => {
"msg": "application_1514971620021_4505\n"
}