loops - Ansible - 循环列表并写入其中

标签 loops ansible conditional-statements

我是 ansible 初学者,我对 ansible playbook 存在疑问,该 playbook 应该从多个服务器收集有关系统版本的信息。

第一步是收集有关服务器的信息(如果它使用 Jboss 或 Tomcat 以及它在哪里) - 我能够做到这一点并将其存储在如下列表中:

"server_list": [
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/test/knz-batch/eap",
            "pid": "14660",
            "type": "wildfly/jboss",
            "version": "",
            "version_cmd": "/srv/ais/test/knz-batch/eap/bin/standalone.sh --version"
        },
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/test/knz-eap/eap",
            "pid": "20153",
            "type": "wildfly/jboss",
            "version": "",
            "version_cmd": "/srv/ais/test/knz-eap/eap/bin/standalone.sh --version"
        },
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/skoleni/knz-ws-int/eap",
            "pid": "24861",
            "type": "wildfly/jboss",
            "version": "",
            "version_cmd": "/srv/ais/skoleni/knz-ws-int/eap/bin/standalone.sh --version"
        },
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/skoleni/knz-ws/wildfly",
            "pid": "25195",
            "type": "wildfly/jboss",
            "version": "",
            "version_cmd": "/srv/ais/skoleni/knz-ws/wildfly/bin/standalone.sh --version"
        },
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/skoleni/knz-ws/undertow",
            "pid": "25667",
            "type": "tomcat",
            "version": "",
            "version_cmd": "/srv/ais/skoleni/knz-ws/undertow/bin/version.sh --version"
        },
        {
            "hostname": "tst-24.ph.koop.cz",
            "path": "/srv/ais/skoleni/knz/wildfly",
            "pid": "26446",
            "type": "wildfly/jboss",
            "version": "",
            "version_cmd": "/srv/ais/skoleni/knz/wildfly/bin/standalone.sh --version"
        }
    ]

现在我需要运行其他 shell 命令(将使用 version_cmd)来获取该版本(使用 GREP)。

但是我不知道循环时如何写入列表。第二个问题是如何创建更多条件(为wildfly/jboss使用其他正则表达式)

    - name: Get server version
      shell: "{{item.version_cmd}}| grep -Po {{ regexp_tomcat_version }}"
      loop: "{{ server_list }}"
      loop_control:
        label: "Check version for {{ item.path }}"
      when: item.type == "tomcat"
      register: server_list.version
      vars:
        regexp_tomcat_version: 'Server version:\s*([^(\n)]*)'
      ignore_errors: yes

这在 Ansible 中可能实现吗?

最佳答案

例如,给出下面的测试列表

server_list:
  - hostname: srv1
    path: /usr/bin/cc
    type: prod
    version_cmd: cc --version
    version_parse: awk 'FNR == 1 {print $4}'
  - hostname: srv1
    path: /usr/local/bin/python
    type: devel
    version_cmd: python --version
    version_parse: awk 'FNR == 1 {print $2}'
  - hostname: srv2
    path: /usr/bin/cc
    type: prod
    version_cmd: cc --version
    version_parse: awk 'FNR == 1 {print $4}'
  - hostname: srv2
    path: /usr/local/bin/python
    type: devel
    version_cmd: python --version
    version_parse: awk 'FNR == 1 {print $2}'

在第一个play中创建动态主机名组并在第二个play中运行它。在第二次播放中,将版本注册到变量server_list_versions中。然后迭代ansible_play_hosts并创建字典versions

- name: Create group server_group
  hosts: localhost
  tasks:
    - add_host:
        name: "{{ item }}"
        groups: server_group
        server_list: "{{ server_list }}"
      loop: "{{ server_list|map(attribute='hostname')|unique }}"

- name: Collect versions
  hosts: server_group
  gather_facts: false
  tasks:
    - shell: "{{ item.version_cmd }}|{{ item.version_parse }}"
      loop: "{{ server_list|selectattr('hostname', 'eq', inventory_hostname) }}"
      loop_control:
        label: "Check version for {{ item.path }}"
      # when: item.type == "devel"
      register: server_list_versions
    - set_fact:
        versions: "{{ versions|d({})|
                      combine({item: hostvars[item].server_list_versions.results|
                                     json_query('[].{path: item.path,
                                                     version: stdout,
                                                     stderr: stderr}')}) }}"
      loop: "{{ ansible_play_hosts }}"
      run_once: true

给出

versions:
  srv1:
    - path: /usr/bin/cc
      stderr: ''
      version: 11.0.1
    - path: /usr/local/bin/python
      stderr: ''
      version: 3.8.12
  srv2:
    - path: /usr/bin/cc
      stderr: ''
      version: 11.0.1
    - path: /usr/local/bin/python
      stderr: '/bin/sh: python: not found'
      version: ''

如果您想更新server_list中的属性version,请创建一个字典

    - set_fact:
        vers_dict: "{{ vers_dict|d({})|
                       combine({item: hostvars[item].server_list_versions.results|
                                      json_query('[].{path: item.path,
                                                      version: stdout}')|
                                      items2dict(key_name='path',
                                                 value_name='version')}) }}"
      loop: "{{ ansible_play_hosts }}"
      run_once: true

给出

vers_dict:
  srv1:
    /usr/bin/cc: 11.0.1
    /usr/local/bin/python: 3.8.12
  srv2:
    /usr/bin/cc: 11.0.1
    /usr/local/bin/python: ''

然后,使用这个字典来更新属性版本

    - set_fact:
        server_list_new: "{{ server_list_new|d([]) +
                             [item|combine({'version': version})] }}"
      loop: "{{ server_list }}"
      vars:
        version: "{{ vers_dict[item.hostname][item.path] }}"
      run_once: true

给出

server_list_new:
  - hostname: srv1
    path: /usr/bin/cc
    type: prod
    version: 11.0.1
    version_cmd: cc --version
    version_parse: awk 'FNR == 1 {print $4}'
  - hostname: srv1
    path: /usr/local/bin/python
    type: devel
    version: 3.8.12
    version_cmd: python --version
    version_parse: awk 'FNR == 1 {print $2}'
  - hostname: srv2
    path: /usr/bin/cc
    type: prod
    version: 11.0.1
    version_cmd: cc --version
    version_parse: awk 'FNR == 1 {print $4}'
  - hostname: srv2
    path: /usr/local/bin/python
    type: devel
    version: ''
    version_cmd: python --version
    version_parse: awk 'FNR == 1 {print $2}'

关于loops - Ansible - 循环列表并写入其中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71604503/

相关文章:

PHP Loop 为每 10、20、30 等执行操作

python - 如何在列表列表中强制单独处理相同的元素?

c++ - 将一个循环分解为两个循环的性能

vagrant - ansible sudo_user 挂起几分钟然后失败(在 centos6.5.1 vagrant vm 中)

javascript - 从数组中随机抓取 3 个项目,其中第 3 个项目可以是 “restaurant",但不一定是

java - 在虚拟机中安装 java 时出错。(Vagrant 和 Ansible)

ansible - 如何检查 Ansible 中是否存在文件?

Python 条件语句

jQuery 动画循环不工作

php - 用小数制作一个简单的for循环