Ansible - 循环列表并写入其中

发布于 2025-01-16 14:31:09 字数 2514 浏览 0 评论 0原文

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

第一步是收集有关服务器的信息(如果它使用 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 中是否可能?

I am ansible beginner and I have a problem with ansible playbook that should gather info about system version from multiple servers.

First step was to gather info about server (if it uses Jboss or Tomcat and where it is) - I was able to do it and store it in list like this:

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

Now I need to run other shell command (that will use version_cmd) to get that version (with use of GREP).

But I don't know how to write into list when looping through. And second problem is how to make more conditions (to use other regex for 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

Is this thing even possible in Ansible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

偏爱你一生 2025-01-23 14:31:09

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

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

在第一次播放中创建动态主机名组并在第二次播放中运行它。在第二次播放中,将版本注册到变量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: ''

然后,使用此字典更新属性 version

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

For example, given the list below for testing

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

Create a dynamic group of hostnames in the first play and run it in the second play. In the second play, register the versions into the variable server_list_versions. Then iterate ansible_play_hosts and create the dictionary 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

gives

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: ''

If you want to update the attribute version in server_list create a dictionary

    - 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

gives

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: ''

Then, use this dictionary to update the attribute version

    - 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

gives

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}'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文