2

I would like to extract some words from an Ansible output. For example, I would like to extract from sudo monit status command the bolded words(** **) and store them in 2 variables(let's say variable 'A' for OK and variable 'B' for the uptime period) which will be used later on into a Jinja2 template:

[ansible@server ~]$ sudo monit status
Monit 5.25.1 uptime: 3m

System 'server'
  status                       **OK**
  monitoring status            Monitored
  monitoring mode              active
  on reboot                    start
  load average                 [0.03] [0.07] [0.11]
  cpu                          0.1%us 0.2%sy 0.0%wa
  memory usage                 338.1 MB [18.4%]
  swap usage                   0 B [0.0%]
  uptime                       **29m**
  boot time                    Fri, 30 Mar 2018 11:56:12
  data collected               Fri, 30 Mar 2018 12:25:24

To accomplish this, I have started an Ansible playbook, but in this way, I'm taking all information from the output:

--- #Health check
- hosts: appserver
  connection: ssh 
  sudo: yes 
  user: ansible
  tasks:
  - name: Monitor the status
    shell: "{{item}}"
    with_items:
      - monit status 
    register: monitinfo
    tags: basic_monitoring
  - debug: var=monitinfo

Any idea how this can be accomplished?

Thank you,

Romain

Romain
  • 171
  • 1
  • 3
  • 15

1 Answers1

2

I see two methods to solve your issue:

Method 1: Converting the shell output to YAML or JSON and parse it with from_yaml or from_json

In your particular case, as the output is already pre-formatted in a key-value way, it would be most convenient to just convert it to a format that Ansible understands (e.g. YAML/JSON). For example, you could convert the output to YAML by deleting the irrelevant lines with tail and then use the regex_replace filter for the rest. Afterwards, use the from_yaml filter to parse everything into Ansible variables. Example:

- name: Fetch the monit status
  shell: "monit status | tail -n +3"
  register: monit_status_raw
- name: Extract monit variables
  set_fact:
     monit_status: "{{ monit_status_raw.stdout | regex_replace('\s\s([a-z]+\s[a-z]*)\s+', '\\1: ') | regex_replace('\s:', ':') | regex_replace('([a-z])\s([a-z])', '\\1_\\2')  | from_yaml }}"
- name: Show server status 
  debug: var=monit_status['status']
- name: Show server uptime
  debug: var=monit_status['uptime']

If everything went fine, the monit_status variable should contain a dictionary of all variables that the monit status command provided. You can access the variables you want as shown in the debug commands within the example above. In case the code does not work already, you could debug the regex_replace filter with

- debug: msg="{{ monit_status_raw.stdout | regex_replace('\s\s([a-z]+\s[a-z]*)\s+', '\\1: ') | regex_replace('\s:', ':') | regex_replace('([a-z])\s([a-z])', '\\1_\\2')  | from_yaml }}"

and check whether the output is really YAML already. In case not, the regular expression has to be adjusted so that in the end, the output is YAML-conform.

Method 2: Searching for the values you need with the regex_search filter

In similar cases where just a single variable has to be extracted or if the output cannot be easily converted to JSON or YAML with regex_replace, the regex_search filter would be the right choice. In your case, the regex_search solution would look similar to this:

- name: Fetch the monit status
  shell: "monit status | tail -n +3"
  register: monit_status_raw
- name: Extract monit variables
  set_fact:
     monit_status: "{{ monit_status_raw.stdout | regex_search('\s\sstatus\s+(.*)') }}"
     monit_uptime: "{{ monit_status_raw.stdout | regex_search('\s\suptime\s+(.*)') }}"
- name: Show server status 
  debug: var=monit_status
- name: Show server uptime
  debug: var=monit_uptime

Hint: Online regex testers like regex101.com can help you to find the right expression.

  • Your solution might work, but the regex part is faulty. I have tried many things, but nothing seems to match. Any idea how this regex can be fixed? Thank you in advance. – Romain Apr 02 '18 at 11:52
  • I slightly adjusted the regex examples so that they should really match your exact use case. If my answer did help you, I'd be happy if you could give it a vote up and/or mark it as your accepted answer. Good luck! – Patrick Fink Apr 02 '18 at 17:09
  • It's not perfectly done(still are some errors in the set_fact, but I will try more with regex101.com). Thanks for the hint – Romain Apr 07 '18 at 14:38
  • When you found the missing part, it would be great if you could edit my answer with your fixes! – Patrick Fink Apr 08 '18 at 19:04