Search code examples
ansiblejinja2assert

Remove only trailling whitespaces from stdout_lines


I need to assert the policy-maps from Cisco devices. And Cisco for some reason adds trailing whitespaces on some lines, but not all. I want to remove them, but, only the trailing whitespaces.

- name: Get running class-map & policy-map config
  vars:
    ansible_connection: network_cli
  ios_command:
    commands:
      - 'show run | sec class-map|policy-map'
  register: show_policy

- name: Print trim
  debug:
    var: show_policy.stdout_lines | trim

- name: Ansible block with assert module
  block:
    - name: Validate running line
      ansible.builtin.assert:
        that:
          - "lookup('template', 'policy_desired.j2').splitlines() in show_policy.stdout_lines"
        success_msg: "TEST: {{ UNIT_HOSTNAME }}: VALIDATE RUNNING POLICY: PASSED"
        fail_msg: "TEST: {{ UNIT_HOSTNAME }}: VALIDATE RUNNING POLICY: FAILED"

This gives the following output:

{
    "show_policy.stdout_lines | trim": [
        [
            "class-map match-any CM-QOS-GENERIC-BESTEFFORT-MARK",
            "  description Generic - Best Effort",
            " match access-group name ACL-QOS-GENERIC-BESTEFFORT",
            "class-map match-any CM-QOS-1P3Q-Q1",
            " match dscp cs4  cs5  ef ",        <--- Notice the whitespace
            "class-map match-any CM-QOS-1P3Q-Q2",
            " match dscp cs6  cs7 ",
            "class-map match-any CM-QOS-1P3Q-Q3",
            " match dscp cs1 "
        ]
    ]
}   

The filter should then be added in the assert module so that it is gone when being asserted.

I have tried multiple things, but nothing seems to do the trick:

- name: Print trim
  debug:
    var: show_policy.stdout_lines | trim

- name: Print trim
  debug:
    var: show_policy.stdout_lines | strip

- name: Print trim
  debug:
    var: show_policy.stdout_lines.strip()

- name: Print trim
  debug:
    var: "{{ show_policy.stdout_lines | map('trim') }}"

- name: Print trim
  debug:
    var: "{{ show_policy.stdout_lines | trim }}"

Solution

  • You can use a regex_replace filter in order to achieve that.

    Note: It seems, from you debug of show_policy.stdout_lines that it is actually a list of list, so you need the trim to happen on show_policy.stdout_lines.0.

    Mind that, in the example below, I am purposely using a YAML multiline syntax, to save me from escaping the backslashes.
    If you don't want to use this syntax, you will have to escaping those backslashes by doubling them (i.e. \\1 and \\s instead of \1 and \s).

    - debug:
        msg: >-
          {{
            show_policy.stdout_lines.0 | map('regex_replace', '(.*)\s+$', '\1')
          }}
    

    Given the task:

    - debug:
        msg: >-
          {{
            show_policy.stdout_lines | map('regex_replace', '(.*)\s+$', '\1')
          }}
      vars:
        show_policy:
          stdout_lines:
            -
              - "class-map match-any CM-QOS-GENERIC-BESTEFFORT-MARK"
              - "  description Generic - Best Effort"
              - " match access-group name ACL-QOS-GENERIC-BESTEFFORT"
              - "class-map match-any CM-QOS-1P3Q-Q1"
              - " match dscp cs4  cs5  ef "
              - "class-map match-any CM-QOS-1P3Q-Q2"
              - " match dscp cs6  cs7 "
              - "class-map match-any CM-QOS-1P3Q-Q3"
              - " match dscp cs1 "
    

    This yields:

    msg:
      - class-map match-any CM-QOS-GENERIC-BESTEFFORT-MARK
      - '  description Generic - Best Effort'
      - ' match access-group name ACL-QOS-GENERIC-BESTEFFORT'
      - class-map match-any CM-QOS-1P3Q-Q1
      - ' match dscp cs4  cs5  ef'
      - class-map match-any CM-QOS-1P3Q-Q2
      - ' match dscp cs6  cs7'
      - class-map match-any CM-QOS-1P3Q-Q3
      - ' match dscp cs1'