Ansible - 使用注册的变量值查找 [英] Ansible - Find using registered variable value
问题描述
我想在这里实现的目标如下
What I am trying to achieve here is as below
- 从 tar.gz 解压缩代码 - 工作
- 在未归档的目录中查找文件名 - 工作
- 根据第 2 步中获取的文件名在代码目录中查找文件名 - 失败
- 从源复制文件:(第 2 步)目标:(第 3 步)- 如果我在第 3 步的模式部分使用硬编码的文件名,则工作
下面提到的是我用过的 Ansible 角色:
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') }}"
在这里,我需要使用 find 根据模式(文件名)在/opt 目录中定位文件,正是我在/tmp 中未归档的文件
最后,根据文件名和路径将文件从/tmp 替换为/opt(我可以这样做).目录结构如下:
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
我需要一个解决方案来替换模式的硬编码:file1、file2 和 file3,并使用一些变量来做到这一点.我需要替换的/tmp 和/opt 中的文件名完全相同
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
推荐答案
如果我理解正确,这里有一种可能的方法来处理您正在尝试做的事情.在下面的示例中,我删除了未归档作业,因为它不在关键路径上.
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.
我创建了两个示例目录.前两个任务只是为了进一步向您展示这个测试结构:
I created two sample directories. The first two tasks are only there to further show you this test structure:
- 一个
archive
目录,包含随机目录中的 4 个文件.其中之一不存在于目标中 - 一个
code
目录,包含几个文件随机目录.3 个文件与archive
中的其他文件具有相同的基本名称.
- an
archive
directory containing 4 files in random directories. One of them is not present in the target - a
code
directory containing several files random directories. 3 files have the same basenames as other files found inarchive
.
第一个 find
任务与您的相同,并注册一个结果,其中包含 archive
目录中所有文件的详细信息.
The first find
task is identical to yours and registers a result with details of all files in the archive
dir.
对于 code
目录中的第二个 find
任务,关键是将基本名称列表作为 patterns
参数传递从您可以使用表达式获得的第一次搜索:
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 }}
我们可以将其详细描述为:从我们的存档 find
结果中获取 files
列表,仅提取 path
属性,应用 basename
过滤器 对每个列表元素和返回一个列表.
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.
对于最后一个任务,我使用了copy
模块.我的示例在 localhost 上运行,但由于您的示例可能会在远程目标上运行,因此必须设置 remote_src
(否则将从控制器获取文件).
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).
循环是在上一个任务的结果上完成的,所以我们只得到代码目录中的匹配文件为dest
.为了选择src
,我们在存档文件夹中查找对应的文件,表达式如下:
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 }}
选择过滤器select
正在应用 match
测试 到列表中的每个路径,仅选择以当前代码路径基名结尾的元素.first
过滤器只获得第一个(并且仅在您的情况下)匹配元素.loop_control.label
用于获得更好的任务结果输出.
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.
前两个任务仅用于调试/演示目的.
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 }}"
结果
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
这篇关于Ansible - 使用注册的变量值查找的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!