簡體   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