Ansible - 使用注册的变量值查找



我在这里要实现的目标如下

  1. 从 tar 中解压缩代码.gz - 正在工作
  2. 在未存档的目录中查找文件名 - 工作
  3. 根据步骤 2 中获取的文件名在代码目录中查找文件名 -失败
  4. 从源复制文件:(步骤 2) 目标:(步骤3) - 如果我在步骤 3 的模式部分中使用硬编码文件名,则可以工作

下面提到的是我使用的 Ansible 角色:

- 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') }}"

在这里,我需要使用 find 根据我在/tmp 中未存档的模式(文件名)在/opt 目录中找到文件

最后,根据文件名和路径将文件从/tmp 替换为/opt(这是我能够做到的)。目录结构如下:

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

在这里,如果我使用以下代码,其中我手动提及文件名,那么它可以工作。但是,我不想那样做

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

我需要一个解决方案来替换模式的硬编码:file1、file2 和 file3,并使用一些变量来做到这一点。我需要替换的/tmp 和/opt 中的文件名完全相同

如果我理解正确,这里有一种可能的方法来处理你正在尝试做的事情。在下面的示例中,我取消了取消存档作业,因为它不在关键路径上。

行动手册演练

  • 我创建了两个示例目录。前两个任务只是为了进一步向您展示此测试结构:

    1. 一个archive目录,包含随机目录中的 4 个文件。其中一个不在目标中
    2. 包含多个文件的code目录 随机目录。3 个文件与在archive中找到的其他文件具有相同的基本名称。
  • 第一个find任务与您的任务相同,并注册一个结果,其中包含archive目录中所有文件的详细信息。

  • 对于code目录中的第二个find任务,关键点是将第一次搜索中的基本名称列表作为参数patterns传递,您可以使用表达式获得该列表:

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

    我们可以将这个详细说明为:从我们的存档find结果中获取files列表,仅提取path属性,对每个列表元素应用basename过滤器并返回一个列表。

  • 对于最后一个任务,我使用了copy模块。我的示例在本地主机上运行,但由于您的示例可能会在远程目标上运行,因此必须设置remote_src(否则将从控制器获取文件)。

    循环是在上一个任务的结果上完成的,因此我们只获取代码目录中的匹配文件作为dest。要选择src,我们使用以下表达式在存档文件夹中查找相应的文件:

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

    选择筛选器selectmatch测试应用于列表中的每个路径,仅选择以当前代码路径基名称结尾的元素。first筛选器仅获取第一个(并且仅在您的情况下)匹配元素。loop_control.label用于获得更好的任务结果输出。

演示手册

前两个任务仅用于调试/演示目的。

---
- 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 }}"

结果

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   

最新更新