How to create conditional copy in Ansible based on

2019-02-23 17:55发布

问题:

I want to copy one version of a file to a server if it has an interface in a specific subnet, or a different version if it does not have an interface in that subnet. Below is a working, but I think less than optimal solution. I'm hoping there is a better way that meets the following criteria...

  • stays dynamic (use facts, I don't want to have to manually set variables for every server and manually create groups for servers in and not in the subnet)
  • less repetitive (could it be handled in one task?)
  • not have to list out every possible interface name (eg. eth0, eth1, ..., bond0, bond1, ... etc)

working version...

- name: copy file version 1 to server
  copy:
    src: files/myfile.vs1
    dest: /etc/myfile
  when: (ansible_eth0.network == "192.168.0.0") or
        (ansible_eth1.network == "192.168.0.0") or
        (ansible_eth2.network == "192.168.0.0")
        ...

- name: copy file version 2 to server
  copy:
    src: files/myfile.vs2
    dest: /etc/myfile
  when: (ansible_eth0.network != "192.168.0.0") and
        (ansible_eth1.network != "192.168.0.0") and
        (ansible_eth2.network != "192.168.0.0")
        ...

回答1:

Some jinja2 ninja tricks and here you are:

- copy:
    src: >-
         {{ (
              ansible_interfaces |
              map('regex_replace','^','ansible_') |
              map('extract',hostvars[inventory_hostname]) |
              selectattr('ipv4','defined') |
              selectattr('ipv4.network','equalto','192.168.0.0') |
              list |
              count > 0
            ) | ternary('files/myfile.vs1','files/myfile.vs2')
         }}
    dest: /etc/myfile

Explanation:

  • take a list of available interfaces from ansible_interfaces
  • prepend all interfaces' names with ansible_ to become (ansible_eth0, etc)
  • extract all interfaces' facts from host own hostvars
  • select only those interfaces where ipv4 is defined
  • select only those interfaces where ipv4.network equals to 192.168.0.0
  • convert to list
  • count
  • if there is one or more such interface return files/myfile.vs1
  • return files/myfile.vs2 otherwise

P.S. >- is used to define multiline string and strip any newlines, otherwise src will be set to files/myfile.vs2\n.