Need to understand how I can write a ansible role so that it compares input / output value.

Hi All,

As I am new to ansible i need to write a role which compares input /output value.

Let me elaborate.

I need to write a role where I already have expected value, for eg hostname of ansible remote node - abc.

Now I need to write a role which first will fetch the value from the remote node and then compare the fetched value with the expected value ( abc ) I have with me.

Thanks.

You need to elaborate some more, I can’t make anything of your story.
Give some real world examples of the tasks that you’re trying to automate.

Thanks for your reply.

I want to automate tasks such as verifying the OS version of remote nodes.

The customer has given me the expected value i.e. Centos version 8.2

Through automation I wish to get the OS version of the remotes nodes and then compare that value with the value that I have received from the customer through ansible playbooks.

That kind of info can be obtained with “gather facts” step, which is the first step when running a playbook.

You just have to comparte returned info in ansible variables like “ansible_distribution” and “ansible_distribution_version” with the expected value. You can store expected value in a local dictionary that uses hostname as the key value.

Hi All,

This is my code:

var

Hi All,

This is my code:

---
# tasks file for uname

      - name: Kernel version number
        register: uname_a
        command: "uname -a"

      - debug:
          var: uname_a.stdout_lines

+++

TASK [uname_tab1 : debug] ***************************************************************************************************************
ok: [192.168.43.237] => {
    "uname_a.stdout_lines": [
        "Linux ansible-client 4.18.0-348.el8.x86_64 #1 SMP Tue Oct 19 15:14:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux"
    ]
}
ok: [192.168.43.6] => {
    "uname_a.stdout_lines": [
        "Linux ansible-client1 4.18.0-348.el8.x86_64 #1 SMP Tue Oct 19 15:14:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux"
    ]
}

++++

Now I need to compare these values with the values given by the customer ( Linux ansible-client1 4.18.0-348.el8.x86_64 ) hence request your assistance out here to write a program.

      Have you considered using "when"?

- name: do something useful
  [....]
   when: uname_a == some_kernel_version_customer_cares about

May probably want to do some cleaning on the uname_a variable first so
it only shows a string that matches what your customer is providing.

What, exactly, do the “values given by the customer” look like? It almost certainly isn’t going to match the output of uname -a. (I’m guessing. But please, don’t make us guess; give us the details of the actual problem.)

Thanks for your reply.

Expected value is: - Linux hostname 4.18.0-193.el8.x86_64 ( The customer has RHEL 8.2 running in its env )
I have 100 such lines given to me by the customer ( OS inventory ) where 80% of the values that I receive by running the ansible standard module matches with the expected value given by the customer. I need to understand how these values can be matched with the values given by the customer.

Assuming “hostname” means a fully qualified domain name, then the following may help you.

---
- hosts: all
  gather_facts: True
  become: false
  tasks:
  - name: show file contents
    debug:
      msg: "{{ lookup('file', 'customer-expects.txt') }}"

  - name: Correct kernel?
    set_fact:
      # These dashes matter.
      expectation: |-
        {%- if lookup('file', 'customer-expects.txt')
              is regex([ansible_system,ansible_fqdn,ansible_kernel]|join(' ')|regex_escape()) -%}
        matched
        {%- else -%}
        missed
        {%- endif -%}

  - name: Report via Debug
    run_once: True
    debug:
      msg: |
        {% for exp in ['missed', 'matched', 'error'] %}
        Kernel_expectations_{{ exp }}:
        {%   for hosti in ansible_play_hosts_all|sort %}
        {%     if hostvars[hosti]['expectation']|d('error') == exp %}
        - {{ hosti }}
        {%     endif %}
        {%   endfor %}

        {% endfor %}

This produces the following output given the command

ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook customer-expects.yml --limit flakey.sample.net,shaggy.sample.net,scooby.sample.net,clyde.sample.net -v

Using /home/utoddl/.ansible.cfg as config file

PLAY [all] ******************************

TASK [Gathering Facts] ****************
fatal: [flakey.sample.net]: UNREACHABLE! => changed=false 
  msg: 'Failed to connect to the host via ssh: [utoddl@flakey.sample.net](mailto:utoddl@flakey.sample.net): Permission denied (publickey,gssapi-keyex,gssapi-with-mic).'
  unreachable: true
ok: [scooby.sample.net]
ok: [shaggy.sample.net]
ok: [clyde.sample.net]

TASK [show file contents] **************
ok: [clyde.sample.net] => 
  msg: |-
    Linux flakey.sample.net 5.15.11-200.fc35.x86_64
    Linux clyde.sample.net 5.15.11-200.fc35.x86_64
    Linux shaggy.sample.net 5.15.11-200.fc35.x86_64
    Linux scooby.sample.net 5.15.11-200.fc35.x86_64
    Linux loaner.sample.net 5.15.11-200.fc35.x86_64

TASK [Correct kernel?] *****************
ok: [clyde.sample.net] => changed=false 
  ansible_facts:
    expectation: matched
ok: [shaggy.sample.net] => changed=false 
  ansible_facts:
    expectation: missed
ok: [scooby.sample.net] => changed=false 
  ansible_facts:
    expectation: matched

TASK [Report via Debug] **************
ok: [clyde.sample.net] => 
  msg: |-
    Kernel_expectations_missed:
    - shaggy.sample.net
  
    Kernel_expectations_matched:
    - clyde.sample.net
    - scooby.sample.net
  
    Kernel_expectations_error:
    - flakey.sample.net

PLAY RECAP ***************************
clyde.sample.net     : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
shaggy.sample.net    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
flakey.sample.net    : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
scooby.sample.net    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Thanks Todd, appreciate your guidance.

Hi Todd,

Thanks for assisting me on it, I did configure the playbook on my test machines and here is the output:

root@ansible-master /]# ansible-playbook hostname1.yml

PLAY [all] ******************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************
ok: [ansible-client]
ok: [ansible-client1]

TASK [show file contents] ***************************************************************************************************************
ok: [ansible-client] => {
“msg”: “Linux ansible-client 4.18.0-348.el8.x86_64\nLinux ansible-client1 4.18.0-348.el8.x86_64”
}
ok: [ansible-client1] => {
“msg”: “Linux ansible-client 4.18.0-348.el8.x86_64\nLinux ansible-client1 4.18.0-348.el8.x86_64”
}

TASK [Correct kernel?] ******************************************************************************************************************
ok: [ansible-client]
ok: [ansible-client1]

TASK [Report via Debug] *****************************************************************************************************************
ok: [ansible-client] => {
“msg”: “Kernel_expectations_missed:\n\nKernel_expectations_matched:\n- ansible-client\n- ansible-client1\n\nKernel_expectations_error:\n\n”
}

PLAY RECAP ******************************************************************************************************************************
ansible-client : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-client1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

[root@ansible-master /]#

Hi Todd,

Can you please let me know how you have entered expected values in customer-expects.txt ( in the sample playbook that you had provided earlier )

Right. I did say “Assuming “hostname”means a fully qualified domain name”, which is not the case. Change ansible_fqdn to ansible_hostname in the “Correct kernel?” task and see if that helps.

Also, if you prefix your ansible-playbook command with ANSIBLE_STDOUT_CALLBACK=yaml (or export the environment variable) you may have more joy looking at your output.

I just used a text editor (“ne”, not that it matters) and followed the example you provided.

How is your customer providing those values to you?

Hi Todd,

Our customer has provided the values in a excel document

For eg:

Expected value
Red Hat Enterprise Linux release 8.2 (Ootpa)
Linux hostname 4.18.0-193.el8.x86_64
Linux hostname 4.18.0-193.el8.x86_64
Installed Packeages
FJSVsnap.noarch 7.00-1 @System

The goalpost keeps moving! Is this (the six lines of data below) from one column of an Excel sheet? From what you described before, I expected

Linux hostname00 4.18.0-193.el8.x86_64
Linux hostname01 4.13.2-120.el8.x86_64
Linux hostname03 4.18.0-193.el8.x86_64
Linux hostname04 4.13.2-120.el8.x86_64
[...etc...]

But now I’m seeing two identical lines following that pattern, mixed with other lines we’ve not heard about before, and nothing to map the “^Linux” lines to actual hosts’ names.

Or is the “Expected value” one column heading, while “Installed Packeages” [sic] is a second column heading and it just got stuck under the first b/c it was exported from Excel as a .txt file? But which host(s) are the Installed Packages matched up with, and how? Or maybe there’s a separate sheet per host in the Excel workbook? It looks like it didn’t survive exporting from Excel particularly well.

And, now that I’m seeing the “Installed Packeages” bit, I’m expecting that to turn into one or more Ansible “package” module steps, in which case there’s some other non-trivial work ahead to transform this requirements-as-spreadsheet into actionable Ansible yaml inputs, in which case the prior exercise is probably moot.

I really want this to work for you. Perhaps it would be helpful to provide the input data spreadsheet as provided by the customer before it’s undergone exporting or other transformations. Although I understand if you need to obfuscate hostnames. If you do, don’t change them all to the same string. Are the two instances of “hostname” below really literally “hostname” (and therefore identical), or do they stand in for originally distinct hosts’ names? And how do those hosts map to sets of installed packages?