[英]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.