Searching for content

It is relatively common in Ansible to search a string for a substring. In particular, the common administrator task of running a command and grepping the output for a particular key piece of data is a reoccurring construct in many playbooks. While it's possible to replicate this with a shell task to execute a command, and pipe the output into grep, and use careful handling of failed_when to catch grep exit codes, a far better strategy is to use a command task, register the output, and then utilize the Ansible provided regex filters in later conditionals.

Let's look at two examples: one using the shell, pipe, grep method, and another using the search test:

- name: check database version 
  shell: neutron-manage current | grep juno 
  register: neutron_db_ver 
  failed_when: false  
- name: upgrade db 
  command: neutron-manage db_sync 
  when: neutron_db_ver | failed 

The preceding example works by forcing Ansible to always see the task as successful, but assumes that if the exit code from the shell is non-zero, then the string juno was not found in the output of the neutron-manage command. This construct is functional but complex to read, and could mask real errors from the command. Let's try again using the search test.

As we stated previously regarding task status, using search on a string in Ansible is considered as a test, and is deprecated. Although it might read slightly odd, to be compliant with Ansible 2.9 and later versions, we must use the keyword is in place of the pipe when using search in this context:

- name: check database version 
  command: neutron-manage current 
  register: neutron_db_ver  
- name: upgrade db 
  command: neutron-manage db_sync 
  when: not neutron_db_ver.stdout is search('juno') 

What we are saying here is, run the task named upgrade db when neutron_db_ver.stdout does not contain the string juno. Once you get used to the concept of when: not ... is, you can see that this version is much cleaner to follow and does not mask errors from the first task.

The search filter searches a string and will return True if the substring is found anywhere within the input string. If an exact complete match is desired instead, the match filter can be used. Full Python regex syntax can be utilized inside the search/match string.