Search code examples
ansiblejinja2chef-infracomparison-operators

Ansible Conditional - Compare registered variable to a value


I need your help since I'm at a complete loss here. We started checking Ansible as a configuration manager (the AWX Project). We are currently based on a Chef Infra configuration manager. In chef when you want to control a resource from happening you can use only_if or not_if

filesystem "Test mount" do
    fstype "xfs"
    mount "/tmp/test"
    device "/dev/sda"
    action [:create, :enable]
    not_if { File.exists?("/tmp/test") }
end

After checking in Ansible I saw that conditionals are the equivalent for Chef guards.

My problem is this: In my example I'm trying to see if a service exists and if it does, do action A, if not, do action B. This is my playbook:

---
- name: Test of powershell
  hosts: all
  tasks:
  - name: test if ABCD service exists
    win_shell: |
      $a = Get-Service -Name ABCD -ErrorAction SilentlyContinue
      if ($a) {
        return $(Write-Host -NoNewline $true)
      }
      return $(Write-Host -NoNewline $false)
    register: ABCDExists
  
  - name: print ABCDExists value
    debug:
      var: ABCDExists
      verbosity: 3
  
  - name: Write service info if service exists
    win_shell: |
      $a = Get-Service -Name ABCD
      New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
      Set-Content -Path C:\temp\test.txt -Value "$($a | select-object -property *)"
    when: ABCDExists is "True"

  - name: Write service doesn't exists
    win_shell: |
      New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
      Set-Content -Path C:\temp\test.txt -Value "Service ABCD doesn't exists"
    when: ABCDExists is "False"

As you can see, the latest try for the conditional is ABCDExists is "True"\ ABCDExists is "False".

This if after I tried doing: ABCDExists == False ABCDExists == "False" ABCDExists|string() == "False"

I really at a loss here, I cannot understand where to look in Jinja documentation for the comparison operators or such.

Any help would be greatly appreciated.

UPDATE: After testing ABCDExists | bool I managed to skip one of the tasks, but not the one I expected.

These are the logs from the running job (After the change):

ansible-playbook 2.9.10
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/var/lib/awx/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Using /etc/ansible/ansible.cfg as config file
SSH password: 
host_list declined parsing /tmp/awx_183_ngdrbth5/tmph5taum3q as it did not pass its verify_file() method
Parsed /tmp/awx_183_ngdrbth5/tmph5taum3q inventory source with script plugin

PLAYBOOK: powershell_test.yml **************************************************
1 plays in powershell_test.yml

PLAY [Test of powershell] ******************************************************

TASK [Gathering Facts] *********************************************************
task path: /tmp/awx_183_ngdrbth5/project/powershell_test.yml:2
Using module file /usr/lib/python3.6/site-packages/ansible/modules/windows/setup.ps1
Pipelining is enabled.
<server01> ESTABLISH WINRM CONNECTION FOR USER: User@Domain.com on PORT 5985 TO server01
EXEC (via pipeline wrapper)
ok: [server01]
META: ran handlers

TASK [test if ABCD service exists] *****************************************
task path: /tmp/awx_183_ngdrbth5/project/powershell_test.yml:5
Using module file /usr/lib/python3.6/site-packages/ansible/modules/windows/win_shell.ps1
Pipelining is enabled.
<server01> ESTABLISH WINRM CONNECTION FOR USER: User@Domain.com on PORT 5985 TO server01
EXEC (via pipeline wrapper)
changed: [server01] => {
    "changed": true,
    "cmd": "$a = Get-Service -Name ABCD -ErrorAction SilentlyContinue\\nif ($a) {\\n  return $(Write-Host -NoNewline $true)\\n}\\nreturn $(Write-Host -NoNewline $false)",
    "delta": "0:00:00.484379",
    "end": "2020-09-01 01:34:23.412182",
    "rc": 0,
    "start": "2020-09-01 01:34:22.927802",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "True",
    "stdout_lines": [
        "True"
    ]
}

TASK [print ABCDExists value] **********************************************
task path: /tmp/awx_183_ngdrbth5/project/powershell_test.yml:14
ok: [server01] => {
    "ABCDExists": {
        "changed": true,
        "cmd": "$a = Get-Service -Name ABCD -ErrorAction SilentlyContinue\\nif ($a) {\\n  return $(Write-Host -NoNewline $true)\\n}\\nreturn $(Write-Host -NoNewline $false)",
        "delta": "0:00:00.484379",
        "end": "2020-09-01 01:34:23.412182",
        "failed": false,
        "rc": 0,
        "start": "2020-09-01 01:34:22.927802",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "True",
        "stdout_lines": [
            "True"
        ]
    }
}

TASK [Write service info if service exists] ************************************
task path: /tmp/awx_183_ngdrbth5/project/powershell_test.yml:19
skipping: [server01] => {
    "changed": false,
    "skip_reason": "Conditional result was False"
}

TASK [Write service doesn't exists] ********************************************
task path: /tmp/awx_183_ngdrbth5/project/powershell_test.yml:26
Using module file /usr/lib/python3.6/site-packages/ansible/modules/windows/win_shell.ps1
Pipelining is enabled.
<server01> ESTABLISH WINRM CONNECTION FOR USER: User@Domain.com on PORT 5985 TO server01
EXEC (via pipeline wrapper)
changed: [server01] => {
    "changed": true,
    "cmd": "New-Item -Path c:\\\\temp\\\\ -Name \\"text.txt\\" -ItemType File -Force\\nSet-Content -Path C:\\\\temp\\\\test.txt -Value \\"Service ABCD doesn't exists\\"",
    "delta": "0:00:00.531259",
    "end": "2020-09-01 01:34:26.380055",
    "rc": 0,
    "start": "2020-09-01 01:34:25.848796",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "\\r\\n\\r\\n    Directory: C:\\\\temp\\r\\n\\r\\n\\r\\nMode                LastWriteTime         Length Name                                                                  \\r\\n----                -------------         ------ ----                                                                  \\r\\n-a----         9/1/2020   9:34 AM              0 text.txt                                                              \\r\\n\\r\\n\\r\\n",
    "stdout_lines": [
        "",
        "",
        "    Directory: C:\\\\temp",
        "",
        "",
        "Mode                LastWriteTime         Length Name                                                                  ",
        "----                -------------         ------ ----                                                                  ",
        "-a----         9/1/2020   9:34 AM              0 text.txt                                                              ",
        "",
        ""
    ]
}
META: ran handlers
META: ran handlers

PLAY RECAP *********************************************************************
server01    : ok=4    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   



Solution

  • From the debug output for variable ABCDExists we can see a couple of things which might change depending on the existence of service.

           "failed": false,
           "stdout": "True",
    

    We can have the tasks with when: condition as below to compare the boolean value of "failed":

      - name: Write service info if service exists
        win_shell: |
          $a = Get-Service -Name ABCD
          New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
          Set-Content -Path C:\temp\test.txt -Value "$($a | select-object -property *)"
        when: not ABCDExists.failed | bool
    
      - name: Write service does not exists
        win_shell: |
          New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
          Set-Content -Path C:\temp\test.txt -Value "Service ABCD doesn't exists"
        when: ABCDExists.failed | bool
    

    Another way is to compare the text output in "stdout": "True",:

      - name: Write service info if service exists
        win_shell: |
          $a = Get-Service -Name ABCD
          New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
          Set-Content -Path C:\temp\test.txt -Value "$($a | select-object -property *)"
        when: ABCDExists.stdout == 'True'
    
      - name: Write service does not exists
        win_shell: |
          New-Item -Path c:\temp\ -Name "text.txt" -ItemType File -Force
          Set-Content -Path C:\temp\test.txt -Value "Service ABCD doesn't exists"
        when: not ABCDExists.stdout == 'True'
    

    There are some ways to test conditions.