Ansible 用于按属性筛选对象并返回具有此属性集的对象名称列表的JMESpath表达式

Ansible 用于按属性筛选对象并返回具有此属性集的对象名称列表的JMESpath表达式,ansible,jmespath,json-query,Ansible,Jmespath,Json Query,是否可以编写JMESPath表达式以返回设置了特定子属性值的对象名称列表?在下面的示例中,我希望获得fileexists.stat.exists设置为true的所有主机名称的列表 我的目标是使用Ansible hostvars结构来获取存在特定文件的所有主机的列表 { "hostvars": { "oclab1n01.example.org": { "fileexists": { "changed": false, "fa

是否可以编写JMESPath表达式以返回设置了特定子属性值的对象名称列表?在下面的示例中,我希望获得fileexists.stat.exists设置为true的所有主机名称的列表

我的目标是使用Ansible hostvars结构来获取存在特定文件的所有主机的列表

{
"hostvars": {
    "oclab1n01.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": false
            }
        }
    }, 
    "oclab1n02.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": true
            }
        }
    }, 
    "oclab1n03.example.org": {
        "fileexists": {
            "changed": false, 
            "failed": false, 
            "stat": {
                "exists": true
            }
        }
    }
} }
在本例中,我希望得到以下输出

["oclab1n02.example.org", "oclab1n03.example.org"]
简短回答(TL;DR) 是的,这是可能的,但它非常麻烦,因为至少在使用JMESpath方面,对于这种通用查询,源数据集的规范化程度很低

上下文
  • jmespath查询语言
  • 查询深度嵌套对象的对象属性
问题
  • 如何使用筛选器表达式构造jmespath查询
  • 目标是过滤具有任意嵌套对象属性的对象
解决方案
  • 这可以通过jmespath完成,但操作将非常麻烦
  • 一个有问题的问题是:对于这种jmespath查询,源数据集的规范化程度很低
  • 为了构造jmespath查询,我们必须假设所有主要对象键在创建查询之前都是已知的
  • 在这个特定示例中,我们必须知道,在构建jmespath查询之前,有三个主机名,而且只有三个主机名。。。如果我们希望能够灵活地指定任意数量的主机名,那么这不是一个有利的情况
例子 以下(太大)jmespath查询

  [
    {
      "hostname": `oclab1n01.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n01.example.org".fileexists.stat.exists
    }
    ,{
      "hostname": `oclab1n02.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n02.example.org".fileexists.stat.exists
    }
    ,{
      "hostname": `oclab1n03.example.org`
      ,"fileexists_stat_exists":  @.hostvars."oclab1n02.example.org".fileexists.stat.exists
    }
  ]|[? @.fileexists_stat_exists == `true`]|[*].hostname
返回以下所需结果

  [
    "oclab1n02.example.org",
    "oclab1n03.example.org"
  ]
陷阱
  • 这个用例的一个主要缺陷是,对于这种查询,源数据集的规范化程度很低
  • 更扁平的数据结构更容易查询
  • 因此,如果可能,更好的方法是在对源数据集运行jmespath查询之前将其展平
具有不同原始数据集的替代示例 如果将原始数据组织为对象列表,而不是对象中的一组嵌套对象,则搜索、排序和筛选列表将更容易,而无需事先知道所涉及的主机名条目数量

{"hostvars": [
    {"hostname":"oclab1n01.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   false
      ,"we_can_even_still_deeply_nest":{"however":
           {"im_only_doing":"it here","to":"prove a point"}
         }
     }
    ,{"hostname":"oclab1n02.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   true
     }
    ,{"hostname":"oclab1n03.example.org"
      ,"fileexists":        true
      ,"filechanged":       false
      ,"filefailed":        false
      ,"filestat_exists":   true
     }
  ]
}
现在可以轻松查询上述重新规范化的数据集

hostvars|[? @.filestat_exists == `true`]|[*].hostname
看起来像是重复的,为什么您认为“key->record”关系规范化得很差?在salt和ansible等配置管理软件中,它似乎非常惯用,但我确实发现大多数jinja过滤器和JMESPath(正如我今天所了解的那样)在
[val1,val2,val3]| map(f)->[f(val1),f(val2),f(val3)]
中工作得非常好,但在
{key1:val1,key2:val2,key3:val3}map(f)->{key1:f(val1),key2:f>中就没有这么好了(val2),key3:f(val3)}
。这从根本上说很难实现吗?@LLlAMnYP//为什么[…]是一个“键->记录”关系规范化得很差//仅针对此特定上下文,而不是一般情况。正如您所提到的,这是一种经常遇到的数据模式。这里的问题是避免与JMespath对抗,而不是使用它//这从根本上说是很难实现的//不是从根本上。问题是设计器选择将映射数据类型设置为iterable,就像列表类型一样。这只是一个设计决策。请随意考虑类似于关系数据库的情况,其中“行”(列表)比“列映射”更容易迭代。