繁体   English   中英

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

[英]Use rego to compare before and after values from list of inputs

当我运行以下命令时,我可以比较参数 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)
}

正如帕特里克·伊斯特所说,有几个问题。 我想我会分解每一个并提供更多细节。 这是我想出的最终版本: https : //play.openpolicyagent.org/p/rl1p43N5HR

第一个问题:使用parameter var 查找字段

表达式res.change.after.parameterres.change.after引用的对象中查找名为"parameter"的字段。 换句话说, 语法foo.barfoo["bar"] 表达式foo["bar"]从值foo选择字段"bar" (字符串 'bar')。 要解决此问题, res.change.after.parameter res.change.after[parameter]更改为res.change.after[parameter] 现在parameter是指变量。

modifies_instance_class_V1[resource_type] = num {
    some resource_type, 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)
}

第二个问题:使modifies_instance_class为每个键生成一个值

第二个问题是规则会为modifies_instance_class文档生成冲突的值。 p[x] = y { ... }形式的规则生成一个名为p的 JSON 文档,其中xy分别是键和值。 OPA 必须将相同键的冲突值视为运行时错误。

例如,假设 OPA 包含以下数据:

resource_types = {"servers"}

resources = {
  "servers": [{
      "after": {"instance_class": "ic1", "identifier": "id1"},
      "before": {"instance_class": "ic2", "identifier": "id1"}
  }]
}

数据表明有一个resource_type ( "servers" ) 和一台服务器。 服务器的数据表明instance_class字段已更改。

当 OPA 评估规则时,它将搜索满足规则体中所有表达式的变量赋值:

# This is the rule body from above.
some resource_type, 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)

在这种情况下,OPA 会查找resource_typeparameterallmodifiesnum 暂时忽略allmodifies_变量。

在这种情况下,OPA 会找到两组变量赋值:

{resource_type: "servers", parameter: "instance_class", num: 1}
{resource_type: "servers", parameter: "identifier", num: 0}

问题是规则生成了从resource_typenum的映射。 在这种情况下,会产生{"servers": 1}{"servers": 0} 这就是冲突。 哪个文件是正确的?

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

modifies_instance_class_V2[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    modifies := [[res, parameter] |   # NOTE: this generates an array of resource/parameter tuples now.
        some parameter
        my_params[parameter]
        res := all[_]
        res.change.after[parameter] != res.change.before[parameter]
    ]
    num := count(modifies)
}

通过此更改,OPA 将仅找到一组变量分配:

{resource_type: "servers", num: 1}

请注意,如果 OPA 要为resource_type找到其他值,那会很好,因为这些值将是modifies_instance_class生成的文档中的不同键。

第三个问题:如果参数字段在之前或之后丢失怎么办?

还有一个问题需要处理。 在上面的例子中,我们假设查找parameter var 引用的字段总是会返回一个值。 如果不是这种情况怎么办? 如果之前或之后的对象之一缺少字段怎么办?

在这种情况下,引用res.change.after[parameter]res.change.before[parameter]将是undefined 如果任一值未定义,则表达式res.change.after[parameter] != res.change.after[parameter]也未定义( https://www.openpolicyagent.org/docs/latest/#expressions-logical-and )。 如果表达式未定义,则 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]
}

注意:在这种情况下,我们必须使用辅助函数,因为要表达逻辑 OR: https : //www.openpolicyagent.org/docs/latest/#logical-or

几件事:

第一个问题是以这种方式使用res.change.after.parameter会导致问题。 那是使用名为“参数”的键而不是变量。 您必须执行类似res.change.after[parameter] 这应该避免第一个错误..但暴露了下一个(和更大的)问题:

eval_conflict_error: object keys must be unique

问题在于您将它们组合到my_params[parameter]并计算modifies 它会给你一个num与每个resource_typeparameter不同(即,某些资源类型x可能有0instance_class2identifier ),这对于将结果构建为一个的方式很棘手resource_typenum映射(因为每个都有可能 >1 num)

如果你只关心计数,你可以做另一种理解来检查每个资源的每个参数(可能不是最好的选择......但有效)。 该工作的一个例子在这里: https : //play.openpolicyagent.org/p/5T5TntBygd

modifies_instance_class[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    modifies := [res |
        res := all[_]       # For each resource
        # Check if one of the params we care about changed
        changed_params := [p | p := my_params[_]; res.change.after[p] != res.change.before[p]]  
        count(changed_params) > 0
    ]
    num := count(modifies)
}

注意,这个例子是不是非常适合提供任何形式的关于什么改变的反馈,所以作为辅助它可能是有用的,但在其里程可能会有所不同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM