[英]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.parameter
在res.change.after
引用的对象中查找名为"parameter"
的字段。 换句话说, 语法foo.bar
是foo["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 文档,其中x
和y
分别是键和值。 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_type
、 parameter
、 all
、 modifies
和num
。 暂时忽略all
、 modifies
和_
变量。
在这种情况下,OPA 会找到两组变量赋值:
{resource_type: "servers", parameter: "instance_class", num: 1}
{resource_type: "servers", parameter: "identifier", num: 0}
问题是规则生成了从resource_type
到num
的映射。 在这种情况下,会产生{"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_type
的parameter
不同(即,某些资源类型x
可能有0
的instance_class
和2
的identifier
),这对于将结果构建为一个的方式很棘手resource_type
到num
映射(因为每个都有可能 >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.