Open policy agent 使用rego比较输入列表中的前后值

Open policy agent 使用rego比较输入列表中的前后值,open-policy-agent,rego,Open Policy Agent,Rego,当我运行以下命令时,我可以比较参数instance_class的值并计算差异数: modifies_instance_class[resource_type] = num { some resource_type resource_types[resource_type] all := resources[resource_type] modifies := [res | res:= all[_]; res.change.after.instance_class

当我运行以下命令时,我可以比较参数instance_class的值并计算差异数:

modifies_instance_class[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    modifies := [res |  res:= all[_]; res.change.after.instance_class != res.change.before.instance_class]
    num := count(modifies)
}
但是,我希望能够使用相同的代码块来比较列表my_params中包含的不同参数值。我试过以下方法,但不起作用

my_params = {"instance_class", "engine_version", "identifier"}

modifies_instance_class[resource_type] = num {
    some resource_type
    some parameter
    resource_types[resource_type]
    my_params[parameter]
    all := resources[resource_type]
    modifies := [res |  res:= all[_]; res.change.after.parameter != res.change.before.parameter]
    num := count(modifies)
}
两件事:

第一个问题是以这种方式使用res.change.after.parameter会导致问题。即使用名为parameter的键,而不是变量。您必须在[parameter]之后执行res.change.after之类的操作。这样可以避免第一个错误。。但也暴露了下一个更大的问题:

评估冲突错误:对象键必须唯一

问题在于,在使用my_params[parameter]和计算修改数的情况下,如何组合它们。它将为每个资源类型提供一个与参数不同的num,例如,某些资源类型x的实例类num为0,标识符num为2,这对于将结果构造为资源类型到num的映射的方式来说是很棘手的,因为每个资源类型都可能>1 num

如果你只关心计数,你可以做另一个理解,检查每个资源的每个参数,这可能不是最好的选择。。但这是有效的。该工作的一个例子如下:


请注意,此示例对于提供有关更改内容的任何反馈都不是很好,因此作为帮助者,它可能很有用,但其里程数可能会有所不同。

如Patrick East所述,有几个问题。我想我应该把每一个都分解一下,提供更多的细节。以下是我提出的最终版本:

第一个问题:使用参数var查找字段 表达式res.change.after.parameter在res.change.after引用的对象中查找名为parameter的字段。换句话说。表达式foo[bar]从值foo中选择字段栏字符串“bar”。要解决此问题,请将res.change.after.parameter更改为res.change.after[parameter]。现在参数引用变量

修改\u实例\u类\u V1[资源\u类型]=num{ 某些资源类型、参数 资源类型[资源类型] 我的参数[参数] 全部:=资源[资源类型] 修改:=[res | res:=all[|];res.change.在[参数]之后!=res.change.在[参数]之前] num:=countmodifies } 第二个问题:使修改\实例\类为每个键生成一个值 第二个问题是,规则将为modifies_instance_类文档生成冲突的值。形式为p[x]=y{…}的规则生成一个名为p的JSON文档,其中x和y分别是键和值。OPA必须将同一密钥的冲突值视为运行时错误

例如,想象OPA包含以下数据:

资源类型={servers} 资源={ 服务器:[{ 之后:{instance_class:ic1,标识符:id1}, 前:{instance_class:ic2,标识符:id1} }] } 数据表明有一个资源类型服务器和一个服务器。服务器的数据表示实例类字段已更改

OPA计算规则时,将搜索满足规则体中所有表达式的变量赋值:

这是上面的规则体。 某些资源类型、参数 资源类型[资源类型] 我的参数[参数] 全部:=资源[资源类型] 修改:=[res | res:=all[|];res.change.在[参数]之后!=res.change.在[参数]之前] num:=countmodifies 在这种情况下,, OPA查找资源类型、参数、全部、修改和数量的值。暂时忽略所有、修改和u变量

在这种情况下,OPA将找到两组变量分配:

{resource_type: "servers", num: 1}
{资源类型:服务器,参数:实例类,num:1} {资源类型:服务器,参数:标识符,num:0} 问题是规则生成了从资源类型到num的映射。在本例中,这将生成{servers:1}和{servers:0}。这就是冲突。哪个文件是正确的

为了解决这个问题,我们可以简单地将my_params[parameter]表达式移动到数组体中

修改\u实例\u类\u V2[资源\u类型]=num{ 某些资源类型 资源类型[资源类型] 全部:=资源[资源类型] 修改:=[[res,parameter]|注意:这将立即生成一个资源/参数元组数组。 某些参数 我的参数[参数] res:=全部 res.change.after[参数]!=res.change.before[参数] ] num:=countmodifies } 通过此更改,OPA将只找到一组变量分配:

{resource_type: "servers", num: 1}
注意,如果OPA要为resource_type找到其他值,那就好了,因为这些值在modifies_instance_类生成的文档中是不同的键

第三个问题:如果参数字段在之前或之后丢失怎么办? 还有一个问题要处理。在上面的例子中,我们假设 查找参数var引用的字段将始终返回一个值。如果不是这样呢?如果一个before或after对象缺少字段,该怎么办

在这种情况下,[parameter]之后的参考res.change.或[parameter]之前的参考res.change.将是未定义的。如果任一值未定义,表达式res.change.after[parameter]!=[参数]之后的res.change.after也未定义。如果表达式未定义,OPA无法断言它为真,因此结果不包括在结果中,或者在本例中,不包括由表达式计算的数组

根据数据的性质,这可能重要,也可能不重要。为了解决这个问题,我们可以扩展检查来处理字段一侧或两侧未定义的情况

modifies_instance_class_V3[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    modifies := [[res, parameter] |
        some parameter
        my_params[parameter]
        res := all[_]
        not same_or_both_undefined(res.change.after, res.change.before, parameter)
    ]
    num := count(modifies)
}

same_or_both_undefined(a, b, k) = true {
    a[k] == b[k]
}

same_or_both_undefined(a, b, k) = true {
    not a[k]
    not b[k]
}
注意:在这种情况下,我们必须使用helper函数,因为我们想要表示逻辑OR: