Ansible - Find using registered variable value

限于喜欢 提交于 2020-05-16 06:32:46

问题


What I am trying to achieve here is as below

  1. Unarchive the code from tar.gz - working
  2. Find file names in unarchived directory - working
  3. Find file names in code directory based on file names fetched in step 2 - failed
  4. Copy files from source:(Step 2) destination:(Step3) - working if I use the hardcoded file names in the pattern section of step 3

Below mentioned is the Ansible role I have used:

- name: Unarchive config files to server
  unarchive:
    src: "{{ config_dir }}/config.tar.gz"
    dest: /tmp
    list_files: yes
  register: tar_path

- name: Find file names in unarchived config files
  find:
    paths: "{{ tar_path.dest }}"
    file_type: file
    recurse: yes
  register: tmp_file_path

- name: Find file names in code base
  find:
    paths: /opt
    file_type: file
    recurse: yes
    patterns:
      #Search for file names with the values in tmp_file_path
  register: code_file_path

- set_fact:
    code_files: "{{ code_files|default([]) +
                    [{'path': item, 'name': item|basename}] }}"
  loop: "{{ code_file_path.files|map(attribute='path')|list }}"

- name: copy files
  command: cp "{{ item.0 }}" "{{ item.1.path }}"
  with_together:
    - "{{ tmp_file_path.files|map(attribute='path')|list|sort }}"
    - "{{ code_files|sort(attribute='name') }}"

Here I need to use find to locate files in /opt directory based on pattern(filename) exactly which I have unarchived in /tmp

And finally, replace files from /tmp to /opt based on the file names and paths(This I am able to do). The directory structure is as follows:

shell> tree tmp
tmp
├── file1
├── file2
└── file3

shell> tree opt
opt
├── bar
│   └── file2
├── baz
│   └── file3
└── foo
    └── file1

Here if I use the below code wherein I manually mention the file names, then it works. However, I don't want to do that

- name: Find file names in code base
  find:
    paths: /opt
    file_type: file
    recurse: yes
    patterns:
      - file1
      - file2
      - file3
  register: code_file_path

I need a solution to replace the hardcoding for patterns: file1, file2 and file3 and use some variable to do that. The file names in /tmp and /opt where I need to replace is exactly the same


回答1:


If I understood correctly, here is a possible way to handle what you're trying to do. In the below example, I took away the unarchive job as it's not on the critical path.

Playbook walkthrough

  • I created two sample directories. The first two tasks are only there to further show you this test structure:

    1. an archive directory containing 4 files in random directories. One of them is not present in the target
    2. a code directory containing several files random directories. 3 files have the same basenames as other files found in archive.
  • The first find task is identical to yours and registers a result with details of all files in the archive dir.

  • For the second find task in the code directory, the key point is to pass as patterns parameter the list of basenames from the first search which you can get with the expression:

    {{ search_archive.files | map(attribute='path') | map('basename') | list }}
    

    We can detail this one as: get files list from our archive find result, extract only the path attribute, apply the basename filter on each list element and return a list.

  • For the last task, I used the copy module. My example runs on localhost but since yours will probably run on a remote target, the remote_src has to be set (or files will be fetched from the controller).

    The loop is done on the result of the previous task so we only get the matching files in code directory as dest. To select the src, we look for corresponding files in the archive folder with the following expression:

    {{ search_archive.files | map(attribute='path') | select('match', '^.*/' + item | basename + '$') | first }}
    

    The select filter select is applying the match test to each path in the list selecting only the elements ending with the current code path basename. The first filter get only the first (and only in your case) matching element. loop_control.label is used to get a better output of task result.

Demo playbook

The first two task are only for debugging/demo purpose.

---
- name: Update files from package in code wherever they are
  hosts: localhost
  gather_facts: false

  tasks:

    - name: Capture sample data structure
      command: tree archive code
      register: structure
      changed_when: false

    - name: Show sample data structure
      debug:
        msg: "{{ structure.stdout_lines}}"

    - name: Find files in archive
      find:
        paths: archive
        file_type: file
        recurse: yes
      register: search_archive

    - name: Find files in code matching names in archive
      find:
        paths: code
        file_type: file
        recurse: yes
        patterns:  >-
          {{
            search_archive.files |
            map(attribute='path') |
            map('basename') |
            list
          }}
      register: search_code

    - name: Copy files from archive to code
      vars:
        archive_source: >-
          {{
            search_archive.files |
            map(attribute='path') |
            select('match', '^.*/' + item | basename + '$') |
            first
          }}
      copy:
        remote_src: yes
        src: "{{ archive_source }}"
        dest: "{{ item }}"
      loop: "{{ search_code.files | map(attribute='path') | list }}"
      loop_control:
        label:
          Source: "{{ archive_source }}"
          Destination: "{{ item }}"

Result

PLAY [Update files from package in code wherever they are] *****************************************************************************************************************************************************************************

TASK [Capture sample data structure] ***************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Show sample data structure] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        "archive",
        "├── a_dir",
        "│   └── file2",
        "├── file1.txt",
        "├── file3",
        "└── other_dir",
        "    └── bla",
        "        └── fileX",
        "code",
        "├── dir1",
        "│   └── file1.txt",
        "├── dir2",
        "│   ├── file2",
        "│   ├── pipo",
        "│   └── toto",
        "└── dir3",
        "    └── subdir",
        "        └── file3",
        "",
        "7 directories, 9 files"
    ]
}

TASK [Find files in archive] ***********************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Find files in code matching names in archive] ************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Copy files from archive to code] *************************************************************************************************************************************************************************************************
changed: [localhost] => (item={'Source': 'archive/file1.txt', 'Destination': 'code/dir1/file1.txt'})
changed: [localhost] => (item={'Source': 'archive/a_dir/file2', 'Destination': 'code/dir2/file2'})
changed: [localhost] => (item={'Source': 'archive/file3', 'Destination': 'code/dir3/subdir/file3'})

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost                  : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


来源:https://stackoverflow.com/questions/61439973/ansible-find-using-registered-variable-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!