首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Ansible中将with_subelements循环和with_nested循环组合起来?

如何在Ansible中将with_subelements循环和with_nested循环组合起来?
EN

Stack Overflow用户
提问于 2022-04-22 11:14:01
回答 1查看 72关注 0票数 1

我正在编写一个剧本,以获得部署到Mirantis的UCP/MKE集群中的服务列表,并检查集群中所有的Docker工作人员是否打开了每个外部群集服务端口。

剧本从localhost发出一个API调用,以获得部署到集群的服务的广泛JSON对象,使用jmespath将其简化为仅使用name、ID和端口。

作为另一个游戏,我的剧本在集群中的每个工作人员上运行一个shell命令,以获得一个打开端口的列表。

我想循环遍历每个服务的每个端口,并确认端口是否在每个工作节点上打开。

我的服务/端口数据对象可以如下所示:

代码语言:javascript
复制
[
    {
        "ID": "aefgergergergergerg",
        "Name": "application1_service",
        "Ports": [
            [
                30950,
                "tcp"
            ],
            [
                30951,
                "tcp"
            ]
        ]
    },
    {
        "ID": "sdfthtrhrthrthrthrthtrh",
        "Name": "application2_service",
        "Ports": [
            [
                31190,
                "tcp"
            ]
        ]
    },
...
]

(通过API调用获得,可以通过jmespath查询进行简化:

代码语言:javascript
复制
'[?Endpoint.Ports].{ ID: ID, Name: Spec.Name, Ports: Endpoint.Ports[?contains(@.PublishMode,`ingress`)].[PublishedPort, PublishMode, Protocol] }'

我的工人的开放端口对象如下所示:

代码语言:javascript
复制
ok: [worker1] => {
    "msg": [
        "tcp:31557",
        "tcp:31501",
        "tcp:31556",
        "tcp:31500",
        "tcp:30231",
        "tcp:30230",
        "tcp:30651",
        "tcp:30650"
    ]
}
ok: [worker2] => {
    "msg": [
        "tcp:31557",
        "tcp:31501",
        "tcp:31556",
        "tcp:31500",
        "tcp:30231",
        "tcp:30230",
        "tcp:30651",
        "tcp:30650"
    ]
}
ok: [worker3] => {
    "msg": [
        "tcp:31557",
        "tcp:31501",
        "tcp:31556",
        "tcp:31500",
        "tcp:30231",
        "tcp:30230",
        "tcp:30651",
        "tcp:30650"
    ]
}

获得与

代码语言:javascript
复制
iptables -L DOCKER-INGRESS | awk -F ' {2,}' '($1 == "ACCEPT") && ($6 ~ /dpt/) {print $6}' | sed 's/ dpt//g')

在我看来,我想将一个with_subelements循环(每个给定服务的端口)和一个with_nested循环(我的子元素作为第一个列表,打开的端口作为嵌套列表)组合在一起,但我确信这是不可能的。

这是我的剧本的相关部分(我已经删掉了逻辑,因为它不相关)

代码语言:javascript
复制
- name: Ensure secrets are in the required collections
  hosts: localhost
  gather_facts: false
  vars_files: vars.yaml

[SNIP]

    - name: "Get a list of services from https://{{ endpoint }}/services"
      ansible.builtin.uri:
        url: "https://{{ endpoint }}/services"
        body_format: json
        headers:
          Authorization: "Bearer {{ auth.json.auth_token }}"
        validate_certs: "{{ validate_ssl_certs | default('yes') }}"
      register: services

    - name: "Create a simplified JSON object of services and ports"
      ansible.builtin.set_fact:
        services_ports: "{{ services.json | json_query(jmesquery) }}"
      vars:
        jmesquery: "{{ jmesquery_services }}"

- name: See what ports are open on which workers
  hosts: workers
  gather_facts: false
  become: true
  vars_files: vars.yaml
  tasks:
    - name: Get the list of open ports
      shell: iptables -L DOCKER-INGRESS | awk -F ' {2,}' '($1 == "ACCEPT") && ($6 ~ /dpt/) {print $6}' | sed 's/ dpt//g'
      register: iptables_rules

    - name: debug
      debug:
        msg: "{{ iptables_rules.stdout_lines }}"

和相关的vars.yaml

代码语言:javascript
复制
---
jmesquery_services: '[?Endpoint.Ports].{ ID: ID, Name: Spec.Name, Ports: Endpoint.Ports[?contains(@.PublishMode,`ingress`)].[PublishedPort, PublishMode, Protocol] }'

如何最好地检查这些端口中的每个端口与每个工作人员上的每个开放端口对应的服务?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-22 12:25:41

您使用subelements查找插件是正确的,您应该简单地遍历服务/端口对,并检查iptables_rules.stdout_lines中是否存在这样的端口。

下面是一个包含虚拟数据的示例游戏手册,说明如何做到这一点:

代码语言:javascript
复制
- hosts: localhost
  gather_facts: false
  become: false
  tasks:
    - name: check if all service ports are open
      # Loop over service/port pairs
      loop: "{{ lookup('subelements', services_ports, 'Ports') }}"
      # Set variables for clarity
      vars:
        service_name: "{{ item[0]['Name'] }}"
        iptables_port: "{{ item[1][1] ~ ':' ~ item[1][0] }}"
        iptables_port_exists: "{{ iptables_port in iptables_rules.stdout_lines }}"
      # Fail the module if port is not found
      failed_when: "not iptables_port_exists"
      # For demo, print out the service status
      debug:
        msg: "Service {{ service_name }} is {{ 'up' if iptables_port_exists else 'down' }} on port {{ iptables_port }}"
  # Example data
  vars:
    services_ports:
      - ID: aefgergergergergerg
        Name: application1_service
        Ports:
          - ["30950", "tcp"]
          - ["30951", "tcp"]
      - ID: sdfthtrhrthrthrthrthtrh
        Name: application2_service
        Ports:
          - ["31190", "tcp"]
    iptables_rules:
      stdout_lines: [
        "tcp:30950",
        "tcp:31190",
      ]

这产生的输出如下:

代码语言:javascript
复制
TASK [check if all service ports are open] *************************************
ok: [localhost] => (item=[{'ID': 'aefgergergergergerg', 'Name': 'application1_service'}, ['30950', 'tcp']]) => {
    "msg": "Service application1_service is up on port tcp:30950"
}
failed: [localhost] (item=[{'ID': 'aefgergergergergerg', 'Name': 'application1_service'}, ['30951', 'tcp']]) => {
    "msg": "Service application1_service is down on port tcp:30951"
}
ok: [localhost] => (item=[{'ID': 'sdfthtrhrthrthrthrthtrh', 'Name': 'application2_service'}, ['31190', 'tcp']]) => {
    "msg": "Service application2_service is up on port tcp:31190"
}
fatal: [localhost]: FAILED! => {"msg": "One or more items failed"}

PS!我不熟悉jmespath,但是您可能需要在工作人员上使用hostvars['localhost']['services_ports']来访问在localhost上创建的变量

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71967856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档