2

When I work with static variables it works absolutely fine. But when I try to use dynamic it does not work.

The playbook:

---
- hosts: Swi1
  vars: 
    NewOne: 0
    provider:
      host: "192.168.0.30"
      transport: "cli"
      username: "cisco"
      password: "cisco"
    
  tasks:
    - name: gather facts
      register: iosfacts
      ios_facts:
        provider: "{{ provider }}"
        
    - name: Display the value of the counter
      debug:
        msg: "NewOne={{ NewOne }} / Data type={{ NewOne | type_debug }}"  
        
    - name: interface description
      set_fact: 
        NewOne: " {{ NewOne + 1 }}"
        parents: "interface {{ item.key }}"
      with_dict: "{{ iosfacts.ansible_facts.ansible_net_interfaces }}"
      when: item.value.operstatus == "up"
      
    - debug:
        msg: " This is Debug {{ NewOne }}"

Gives the error:

fatal: [Swi1]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ NewOne + 1 }}): coercing to Unicode: need string or buffer, int found"}

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83

2 Answers2

2

If you want to do an increment on a variable, you need to recast it as an int, as set_fact will always make you end up with a string.

As an example, the two tasks:

- set_fact:
    NewOne: "{{ NewOne | d(0) + 1 }}"

- debug:
    var: NewOne | type_debug

Are giving

TASK [set_fact] ***************************************************************
ok: [localhost]

TASK [debug] ******************************************************************
ok: [localhost] => 
  NewOne | type_debug: str

The fix is, then, to use the int filter.

Given:

- set_fact:
    NewOne: "{{ NewOne | d(0) | int + 1 }}"
  loop: "{{ range(1, 4) }}"

- debug:
    var: NewOne

This yields the expected

TASK [set_fact] ***************************************************************
ok: [localhost] => (item=1)
ok: [localhost] => (item=2)
ok: [localhost] => (item=3)

TASK [debug] ******************************************************************
ok: [localhost] => 
  NewOne: '3'

But then with your use case, there are more elaborated and shorter way to achieve the same:

- set_fact:
    NewOne: >-
      {{ 
        iosfacts
          .ansible_facts
          .ansible_net_interfaces 
        | selectattr('value.operstatus', '==', 'up')
        | length
      }}

Given:

- debug:
    msg: >-
      {{
        iosfacts
          .ansible_facts
          .ansible_net_interfaces
        | selectattr('value.operstatus', '==', 'up')
        | length
      }}
  vars:
    iosfacts:
      ansible_facts:
        ansible_net_interfaces:
          - value:
              operstatus: up
          - value:
              operstatus: down
          - value:
              operstatus: up

This yields:

ok: [localhost] => 
  msg: '2'
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
1

It seems you are trying to implement a loop counter with a programming paradigm, which isn't plain possible in that way since Ansible is not a programming language but a Configuration Management Tool in which you declare a state.

Your current issue is reproducible in the following way:

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    NewOne: 0

  tasks:

  - name: Show var
    debug:
      msg: "{{ NewOne | type_debug }}"

  - name: Add value
    set_fact:
      NewOne: " {{ NewOne + 1 }}"
    loop: [1, 2, 3]

  - name: Show result
    debug:
      msg: "{{ NewOne }}

resulting into an output of

TASK [Add value] *************
ok: [localhost] => (item=1)
fatal: [localhost]: FAILED! =>
  msg: 'Unexpected templating type error occurred on ( {{ NewOne + 1 }}): coercing to Unicode: need string or buffer, int found'

Possible Solutions

You may have a look into Migrating from with_X to loop and Extended loop variables as an iteration counter is already provided there.

An other approach is given via type casting with filter in the answer of @β.εηοιτ.βε.

There as well if you are just interested in the amount of occurrences of certain status, like interface status up or down.

Further Q&A

Further Documentation

U880D
  • 8,601
  • 6
  • 24
  • 40