如何用正则表达式替换 Ansible 中的嵌套值
How to regex replace nested values in Ansible
这个问题是关于 Ansible 中的循环,而不是关于 AWS,但为了清楚起见,我将以 AWS 部署问题为例。
对于我们的部署脚本,我试图循环遍历 Amazon EC2 容器服务中的一些集群。我最终要做的是重启集群上的每项服务。鉴于服务的名称,我可以重新启动服务。但是我需要简单的名称,而不是完全限定的 ARN。所以我查看了每个集群的服务并得到了这样的结果:
results:
- _ansible_item_result: true
_ansible_no_log: false
_ansible_parsed: true
ansible_facts:
services:
- arn:aws:ecs:eu-central-1:55:service/test-services
changed: false
failed: false
invocation:
module_args:
aws_access_key: null
aws_secret_key: null
cluster: services
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
item: services
- _ansible_item_result: true
_ansible_no_log: false
_ansible_parsed: true
ansible_facts:
services:
- arn:aws:ecs:eu-central-1:55:service/test-service
- arn:aws:ecs:eu-central-1:55:service/frontend
- arn:aws:ecs:eu-central-1:55:service/beats
changed: false
failed: false
invocation:
module_args:
aws_access_key: null
aws_secret_key: null
cluster: test-service
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
item: test-service module_args:
aws_access_key: null
aws_secret_key: null
cluster: test-service
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
项目:测试服务
现在我想用服务的简称替换每个 ARN。例如:arn:aws:ecs:eu-central-1:55:service/test-service
变为 test-service
.
替换后我可以循环服务并通过将所需计数设置为 0 来关闭它们(稍后我将再次打开它们):
- name: "Turn services off"
ecs_service:
name: "{{ item[1]}}"
desired_count: 0
task_definition: "{{ taskdefinitions[item[1]] }}"
cluster: "{{ item[0].item }}"
state: present
with_subelements:
- "{{ result.results }}"
- ansible_facts.services
register: turnOffServiceResult
其中 taskdefinitions
是我在剧本中定义的简单字典:
taskdefinitions:
services:
- test-services
test-xde-worker-service:
- test-service
因此,在我将上面显示的 AWS 列表放入变量后 result
我尝试通过执行以下操作来替换正则表达式:
- set_fact:
result:
results:
ansible_facts:
services: "{{ result.results.1.ansible_facts.services | map('regex_replace', '.*/(.*?)$', '\1' ) | list }}"
这很好用,但它显然只替换了一个集群的服务名称,我丢失了字典中的任何其他字段 ansible_facts
。后者是可以接受的,前者不是。所以问题来了:如何替换嵌套列表中的文本?另一个问题是跳过关闭未包含在 taskdefinitions
中的服务,但这不是手头的问题。
我不知道有任何内置方法可以就地修改复杂对象中的任意项(至少在当前的 Ansible 2.3 中)。
您 select 需要原始对象中的项目(使用 select
、map(attribute=...)
、json_query
等),然后修改减少的 [=22= 中的项目].在您使用 JMESPath 的假设示例中,例如 result.results[].ansible_facts.services[]
到 select 所有集群中的所有服务和 map('regex_replace',...
此列表。
或者遍历复杂对象并在循环内应用修改,例如:
- name: "Turn services off"
ecs_service:
name: "{{ myname }}"
desired_count: 0
task_definition: "{{ taskdefinitions[myname] }}"
cluster: "{{ mycluster }}"
state: present
vars:
mycluster: "{{ item[0].item }}"
myname: "{{ item[1] | regex_search('[^/]*$') }}"
with_subelements:
- "{{ result.results }}"
- ansible_facts.services
这个问题是关于 Ansible 中的循环,而不是关于 AWS,但为了清楚起见,我将以 AWS 部署问题为例。
对于我们的部署脚本,我试图循环遍历 Amazon EC2 容器服务中的一些集群。我最终要做的是重启集群上的每项服务。鉴于服务的名称,我可以重新启动服务。但是我需要简单的名称,而不是完全限定的 ARN。所以我查看了每个集群的服务并得到了这样的结果:
results:
- _ansible_item_result: true
_ansible_no_log: false
_ansible_parsed: true
ansible_facts:
services:
- arn:aws:ecs:eu-central-1:55:service/test-services
changed: false
failed: false
invocation:
module_args:
aws_access_key: null
aws_secret_key: null
cluster: services
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
item: services
- _ansible_item_result: true
_ansible_no_log: false
_ansible_parsed: true
ansible_facts:
services:
- arn:aws:ecs:eu-central-1:55:service/test-service
- arn:aws:ecs:eu-central-1:55:service/frontend
- arn:aws:ecs:eu-central-1:55:service/beats
changed: false
failed: false
invocation:
module_args:
aws_access_key: null
aws_secret_key: null
cluster: test-service
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
item: test-service module_args:
aws_access_key: null
aws_secret_key: null
cluster: test-service
details: false
ec2_url: null
profile: null
region: null
security_token: null
service: null
validate_certs: true
项目:测试服务
现在我想用服务的简称替换每个 ARN。例如:arn:aws:ecs:eu-central-1:55:service/test-service
变为 test-service
.
替换后我可以循环服务并通过将所需计数设置为 0 来关闭它们(稍后我将再次打开它们):
- name: "Turn services off"
ecs_service:
name: "{{ item[1]}}"
desired_count: 0
task_definition: "{{ taskdefinitions[item[1]] }}"
cluster: "{{ item[0].item }}"
state: present
with_subelements:
- "{{ result.results }}"
- ansible_facts.services
register: turnOffServiceResult
其中 taskdefinitions
是我在剧本中定义的简单字典:
taskdefinitions:
services:
- test-services
test-xde-worker-service:
- test-service
因此,在我将上面显示的 AWS 列表放入变量后 result
我尝试通过执行以下操作来替换正则表达式:
- set_fact:
result:
results:
ansible_facts:
services: "{{ result.results.1.ansible_facts.services | map('regex_replace', '.*/(.*?)$', '\1' ) | list }}"
这很好用,但它显然只替换了一个集群的服务名称,我丢失了字典中的任何其他字段 ansible_facts
。后者是可以接受的,前者不是。所以问题来了:如何替换嵌套列表中的文本?另一个问题是跳过关闭未包含在 taskdefinitions
中的服务,但这不是手头的问题。
我不知道有任何内置方法可以就地修改复杂对象中的任意项(至少在当前的 Ansible 2.3 中)。
您 select 需要原始对象中的项目(使用 select
、map(attribute=...)
、json_query
等),然后修改减少的 [=22= 中的项目].在您使用 JMESPath 的假设示例中,例如 result.results[].ansible_facts.services[]
到 select 所有集群中的所有服务和 map('regex_replace',...
此列表。
或者遍历复杂对象并在循环内应用修改,例如:
- name: "Turn services off"
ecs_service:
name: "{{ myname }}"
desired_count: 0
task_definition: "{{ taskdefinitions[myname] }}"
cluster: "{{ mycluster }}"
state: present
vars:
mycluster: "{{ item[0].item }}"
myname: "{{ item[1] | regex_search('[^/]*$') }}"
with_subelements:
- "{{ result.results }}"
- ansible_facts.services