Search code examples
ansibleansible-2.x

Unexpected behavior with 'ansible-playbook --limit' and regular expression with lookahead


I have the following test setup and result:

$ cat hosts
[test]
abc-1
abc-ecs
abc-x
ecs-1
ecs-y
$ cat test-regex.yaml 
- name: test
  hosts:
    - test
  tasks:
    - name: set var
      set_fact:
        myvar: "this is a test"
$ cat hosts | sed "s: ::g" | ggrep -P '^(?!ecs).*'
[test]
abc-1
abc-ecs
abc-x
$ ansible-playbook -i hosts -l ~'^(?!ecs).*' test-regex.yaml -D -C --list-hosts --list-tasks
playbook: test-regex.yaml

  play #1 (test): test  TAGS: []
    pattern: ['test']
    hosts (5):
      abc-ecs
      abc-x
      ecs-1
      ecs-y
      abc-1
    tasks:
      set var   TAGS: []

As shown with ggrep, ^(?!ecs).* does not match ecs-1 and ecs-y, but Ansible says it matches, can you explain?

I would like to apply to hosts starting with ecs only. I tested with Ansnile Core 2.13.3.

Also for testing purpose, can I maintain one file instead of two as shown here?


Solution

  • The question of the original post asks why -l ~'^(?!ecs).*' matches every host in the test group:

    [test]
    abc-1
    abc-ecs
    abc-x
    ecs-1
    ecs-y
    

    but not those three abc-* hosts only as intended. This is because -l ~'^(?!ecs).*' not only matches hosts, but groups as well, and ansible creates two default groups: all and ungrouped. In this case, the regular expression matches:

    • test group which contains all 5 hosts listed above
    • all group which contains all 5 hosts listed above
    • ungrouped group which contains 0 hosts
    • abc-1 host
    • abc-x host
    • abc-ecs host

    The union of all above consists the 5 hosts as shown in the output in the original post, so this is an expected behavior. To get what I intended, which is every hosts not starting with ecs, I should exclude the test and all groups also. The regular expression and the intended result are copied below.

    $ ansible-playbook -i hosts -l ~'^(?!ecs|test|all).*' test-regex.yaml -D -C --list-hosts --list-tasks
    
    playbook: test-regex.yaml
    
      play #1 (test): regexcheck    TAGS: []
        pattern: ['test']
        hosts (3):
          abc-1
          abc-x
          abc-ecs
        tasks:
          set var   TAGS: []
    

    The "mystery" resolved.