【问题标题】:YAML using json_query to print specific value array with filter string contained dotYAML 使用 json_query 打印特定值数组,过滤字符串包含点
【发布时间】:2022-11-19 11:33:13
【问题描述】:

我在从某个模块获得的输出中过滤数组时遇到问题。 所以下面是我将它放入某个变量的模块的输出,然后我只想显示/打印该变量的特定值。也许你们可以帮助我?

{
  "extraConfig": [
    {
      "_vimtype": "vim.option.OptionValue",
      "key": "svga.guestBackedPrimaryAware",
      "value": "TRUE"
    },
    {
      "_vimtype": "vim.option.OptionValue",
      "key": "guestOS.detailed.data",
      "value": "bitness='64' distroName='Red Hat Enterprise Linux' distroVersion='8.2' familyName='Linux' kernelVersion='4.18.0-193.el8.x86_64' prettyName='Red Hat Enterprise Linux 8.2 (Ootpa)'"
    }
  ]
}

以上是变量的值概括,那么我只想得到prettyName='红帽企业 Linux 8.2 (Ootpa)', 可能吗?

我试过使用?包含但仍然得到空值,然后我在下面尝试了这个但得到了错误:

致命的:[本地主机]:失败! => {"msg": "jmespath.search in json_query filter plugin:\n'method' object is not iterable"}

- debug:  
    msg: "{{ vmhost_info | json_query(query) }}"
  vars:
    keyvar: 'guestOS.detailed.data'
    query: "instance.config.extraConfig[?key == '{{ keyvar }}'].value"

【问题讨论】:

    标签: ansible yaml


    【解决方案1】:

    看起来您现有的查询非常接近;它返回字符串值:

    bitness='64' distroName='Red Hat Enterprise Linux' distroVersion='8.2' familyName='Linux' kernelVersion='4.18.0-193.el8.x86_64' prettyName='Red Hat Enterprise Linux 8.2 (Ootpa)'

    有几种方法可以获取 prettyName 的值。一种选择是首先将字符串拆分为多行。如果我们在' 上拆分字符串,则每一行都以键名开头。也就是说,这个任务:

    - debug:
        msg: >-
          {{
            (vmhost_info | json_query(query))  |
            first |
            split("' ")
          }}
      vars:
        keyvar: 'guestOS.detailed.data'
        query: "instance.config.extraConfig[?key == '{{ keyvar }}'].value"
    

    结果是:

    TASK [debug] ********************************************************************************************
    ok: [localhost] => {
        "msg": [
            "bitness='64",
            "distroName='Red Hat Enterprise Linux",
            "distroVersion='8.2",
            "familyName='Linux",
            "kernelVersion='4.18.0-193.el8.x86_64",
            "prettyName='Red Hat Enterprise Linux 8.2 (Ootpa)'"
        ]
    }
    

    现在我们有了一个项目列表,每个项目都以键名开头,我们可以使用 select 过滤器来提取 prettyName 值:

    - debug:
        msg: >-
          {{
            (vmhost_info | json_query(query))  | first |
            split("' ") |
            select('match', '^prettyName') | first |
            split('=')
            | last | replace("'", "")
          }}
      vars:
        keyvar: 'guestOS.detailed.data'
        query: "instance.config.extraConfig[?key == '{{ keyvar }}'].value"
    

    哪个产量:

    TASK [debug] ********************************************************************************************
    ok: [localhost] => {
        "msg": "Red Hat Enterprise Linux 8.2 (Ootpa)"
    }
    

    我们使用 select 过滤器仅选择列表中以 prettyName 开头的项目,这为我们提供了单个项目列表。 first 过滤器为我们提供列表中的第一项,然后我们将其拆分为 = 以获得 (key, value) 元组。 last 过滤器为我们提供了值,然后使用 replace 去除单引号。

    【讨论】:

    • 我尝试使用您提供的调试块,但仍然出现错误fatal: [localhost]: FAILED! => {"msg": "template error while templating string: no filter named 'split'. String: {{ (vmhost_info | json_query(query)) | first | split("' ") }}"}
    • 您必须使用旧版本的 Ansible。这已经在 Ansible(核心)2.12.6(和 Jinja2 3.0.2)上进行了测试(并且运行没有错误)。
    【解决方案2】:

    从列表中选择项目

      keyvar: "guestOS.detailed.data"
      data: "{{ vmhost_info.instance.config.extraConfig|
                selectattr('key', 'eq', keyvar)|first }}"
    

    用换行符替换定界空格,用冒号替换等号。创建字典参数

      params: "{{ data.value|replace(pattern1, newline)|
                             replace(pattern2, colon)|
                             from_yaml }}"
      pattern1: "' "
      pattern2: "="
      newline: "'
    "
      colon: ": "
    

      params:
        bitness: '64'
        distroName: Red Hat Enterprise Linux
        distroVersion: '8.2'
        familyName: Linux
        kernelVersion: 4.18.0-193.el8.x86_64
        prettyName: Red Hat Enterprise Linux 8.2 (Ootpa)
    

    用于测试的完整剧本示例

    - hosts: localhost
    
      vars:
    
        vmhost_info:
          instance:
            config:
              extraConfig:
                - _vimtype: vim.option.OptionValue
                  key: svga.guestBackedPrimaryAware
                  value: 'TRUE'
                - _vimtype: vim.option.OptionValue
                  key: guestOS.detailed.data
                  value: >-
                    bitness='64' distroName='Red Hat Enterprise Linux' distroVersion='8.2'
                    familyName='Linux' kernelVersion='4.18.0-193.el8.x86_64'
                    prettyName='Red Hat Enterprise Linux 8.2 (Ootpa)'
    
        keyvar: "guestOS.detailed.data"
        data: "{{ vmhost_info.instance.config.extraConfig|
                  selectattr('key', 'eq', keyvar)|first }}"
    
        params: "{{ data.value|replace(pattern1, newline)|
                               replace(pattern2, colon)|
                               from_yaml }}"
        pattern1: "' "
        pattern2: "="
        newline: "'
    "
        colon: ": "
                
      tasks:
    
        - debug:
            var: params
        - debug:
            var: params.prettyName
    

    给出属性的值名字很好听

      params.prettyName: Red Hat Enterprise Linux 8.2 (Ootpa)
    

    问:“我猜没有简单的方法吧?”

    A: 过滤器community.general.jc 似乎是使其更简单的候选者。但是,不幸的是,它

    • 仅适用于线条

    • 不保留键的大小写,并且

    • 不会删除引号为promised

        params: "{{ data.value|replace(pattern1, newline)|
                               community.general.jc('ini') }}"
        pattern1: "' "
        newline: "'
    "
    

      params:
        bitness: '''64'''
        distroname: '''Red Hat Enterprise Linux'''
        distroversion: '''8.2'''
        familyname: '''Linux'''
        kernelversion: '''4.18.0-193.el8.x86_64'''
        prettyname: '''Red Hat Enterprise Linux 8.2 (Ootpa)'''
    

    【讨论】:

    • 在数组中拆分字符串看起来很长,我猜没有简单的方法?
    • 我添加了一个例子community.general.jc.但是,最简单的方法是自定义过滤器。你想试试吗?
    • 不确定,因为我没有使用社区模块。我会先为它做研究。
    • 它也很强大。你必须安装jc。我推荐它。
    • 如果我使用 ansible tower 下的工人很少,那么我需要为所有工人安装这个“jc”吗? bcs 目前我使用这个 ansi 作为用户,并且有一个团队管理这个 ansi env
    【解决方案3】:

    迟到的答案,但无论如何对其他人有用......

    SO-73629493$ cat test.json
    {
      "extraConfig": [
        {
          "_vimtype": "vim.option.OptionValue",
          "key": "svga.guestBackedPrimaryAware",
          "value": "TRUE"
        },
        {
          "_vimtype": "vim.option.OptionValue",
          "key": "guestOS.detailed.data",
          "value": "bitness='64' distroName='Red Hat Enterprise Linux' distroVersion='8.2' familyName='Linux' kernelVersion='4.18.0-193.el8.x86_64' prettyName='Red Hat Enterprise Linux 8.2 (Ootpa)'"
        }
      ]
    }
    SO-73629493$ ansible localhost -m debug -a "msg={{extraConfig|json_query("[?key=='guestOS.detailed.data'].value")|join("")|regex_replace("^.*prettyName='(.*)'$","")}}" -e @test.json
    localhost | SUCCESS => {
        "msg": "Red Hat Enterprise Linux 8.2 (Ootpa)"
    }
    

    解释:

    json_query 给出了一个包含一个元素的数组,所以我加入它以获取一个字符串。在字符串上,我可以调用带有反向引用的 regex_replace 来获得你想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-17
      相关资源
      最近更新 更多