Range function in Ansible?

2,257 views
Skip to first unread message

Albert Short

unread,
May 8, 2020, 11:49:14 AM5/8/20
to Ansible Project
Can anyone tell me there is a solution I can use to do the same thing a Python range function in Ansible?

Scenario:
Variables I am using
    access_hostname:
    - name: dariusz_access1
      nodeid_access: 1001
      from_port: '04'
      vlanid:
        - 201-204,500-510
      podid: 1
      int_mode: regular
      depl_immediacy: lazy

    - name: dariusz_access2
      nodeid_access: 1001
      from_port: '05'
      vlanid:
        - 10,1200
      podid: 1
      int_mode: regular
      depl_immediacy: lazy

What I want to achieve is to expand my 'vlanid' variable into a list of individual items:
So from this
      vlanid:
        - 201-204,500-510

to something like this, hopefully to the use that info in loops, etc.
      dariusz_access1:
        vlanid:
            - '0201'
            - '0202'
            - '0203'
            - '0204'
            - '0500'
            - '0501'
            - '0502'
            - '0503'
            - '0504'
            - '0505'
            - '0506'
            - '0507'
            - '0508'
            - '0509'
            - '0510'
    - |-
      dariusz_access2:
        vlanid:
            - '0010'
            - '1200'



I also need to get a leading zero '0' added to each vlanid that is not 4 characters in length.

The idea is to avoid having to ask the end user to input each vlanid individually, which could take some time.

I have a python code that can split the ranges for me, with no problem, but if there was an option in Ansible, i would prefer that.

Any guidance would be great.

Dick Visser

unread,
May 8, 2020, 1:55:08 PM5/8/20
to ansible...@googlegroups.com
This works for me:


---
- hosts: localhost
connection: local
gather_facts: no

vars:
vlan_range: 1-9,100-103,201-204,500-507,600-604,1000-1003

tasks:
- set_fact:
vlans: "{{ vlans|default([]) | union(lookup('sequence',
item.split('-')|first + '-' + item.split('-')|last + ':%04d',
wantlist=True )) }}"
loop: "{{ vlan_range.split(',') }}"

- debug: var=vlans


TASK [debug] **********************************************************************************
ok: [localhost] =>
vlans:
- '0001'
- '0002'
- '0003'
- '0004'
- '0005'
- '0006'
- '0007'
- 0008
- 0009
- '0100'
- '0101'
- '0102'
- '0103'
- '0201'
- '0202'
- '0203'
- '0204'
- '0500'
- '0501'
- '0502'
- '0503'
- '0504'
- '0505'
- '0506'
- '0507'
- '0600'
- '0601'
- '0602'
- '0603'
- '0604'
- '1000'
- '1001'
- '1002'
- '1003'



The only thing I don't understand is how to make the formatting
understand that this is decimal - the 0008 and 0009 are treated as
octal.
Adding "map('string') |list" doesn't fix that.


Dick
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/904dbcd3-a1eb-4cf7-95cf-5e9bcf594294%40googlegroups.com.



--
Dick Visser
Trust & Identity Service Operations Manager
GÉANT

Vladimir Botka

unread,
May 8, 2020, 3:06:41 PM5/8/20
to Albert Short, ansible...@googlegroups.com
On Fri, 8 May 2020 08:49:14 -0700 (PDT)
Albert Short <alber...@gmail.com> wrote:

> Scenario:
> Variables I am using
> access_hostname:
> - name: dariusz_access1
> nodeid_access: 1001
> from_port: '04'
> vlanid:
> - 201-204,500-510
> podid: 1
> int_mode: regular
> depl_immediacy: lazy
>
> - name: dariusz_access2
> nodeid_access: 1001
> from_port: '05'
> vlanid:
> - 10,1200
> podid: 1
> int_mode: regular
> depl_immediacy: lazy
>
> What I want to achieve is to expand my 'vlanid' variable into a list of
> individual items:

It's possible to create "filter_plugins"
https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#filter-plugins

For example

shell> cat filter_plugins/my_filters.py
def my_range(s):
interval = str(s).split("-")
start = int(interval[0])
if len(interval) > 1:
stop = int(interval[1]) + 1
else:
stop = start + 1
return [i for i in range(start,stop)]

def my_split(s):
return str(s).split(",")

class FilterModule(object):
def filters(self):
return {
'my_range': my_range,
'my_split': my_split
}

Then this task does the job

- debug:
msg: "{{ item.vlanid|
map('my_split')|flatten|
map('my_range')|flatten }}"
loop: "{{ access_hostname }}"

HTH,

-vlado

Albert Short

unread,
May 11, 2020, 3:41:02 AM5/11/20
to Ansible Project
Dick,

thanks for that, other than the strange behavior for anything with the 8 or 9 in it not formatting correctly.

My next issue I can't resolve is to make this loop through a 'multi-layer' dictionary

    top:
      device1:
        name: test_name1
        vlanid: 2-10,800-810
      device2:
        name: test_name2
        vlanid: 100-120

My brain is a bit frazzled right now but I may be looking at this from the wrong angle.

My idea, if possible is to be able to:
  1. User to input 'name:' for each device/endpoint ('device1:' , 'device2:')
  2. User input of 'vlanid:' for each specific device/endpoint ('device1:' , 'device2:')
  3. Ansible to loop through 'top:'
    1. Use 'name:' input
    2. Expand 'vlanid:'
    3. Build required objects in ACI, on per device/endpoint deployment
If I can get this work once, I hope to be able to use it on other ACI object creations that are endpoint specific. 

I have tried using sub_elements in my past playbook, which works fine, but I have to input each 'vlanid' individually into a list
    top:
      device1:
        name: test_name1
        vlanid: 
           - '0002'
           - '0003'
           - '0004'
           .....
           - '0919'
      device2:
        name: test_name2
        vlanid: 
           - '0100'
           - '0101'
           - '0102'
           - '0103'
           ...
           - '0120'

Again, any assistance would be great.

Regards
> To unsubscribe from this group and stop receiving emails from it, send an email to ansible...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages