2015-12-05 118 views
1

我正在嘗試編寫一個JQ過濾器,用於根據資源屬性從AWS cloudformation模板中過濾特定資源。使用JQ過濾cloudformation堆棧資源

例如,從以下的(縮短)cloudformation模板開始時:

{ 
"Resources": { 
"vpc001": { 
    "Type": "AWS::EC2::VPC", 
    "Properties": { 
    "CidrBlock": "10.1.0.0/16", 
    "InstanceTenancy": "default", 
    "EnableDnsSupport": "true", 
    "EnableDnsHostnames": "true" 
    } 
}, 
"ig001": { 
    "Type": "AWS::EC2::InternetGateway", 
    "Properties": { 
    "Tags": [ 
     { 
     "Key": "Name", 
     "Value": "ig001" 
     } 
    ] 
    } 
} 
} 
} 

我想構建JQ-濾波器使我能夠濾除基於(一個或多個)的特定資源的屬性字段。

例如:

用於type = 「AWS :: EC2 :: InternetGateway」 過濾時

結果應該是

{ 
"Resources": { 
"ig001": { 
    "Type": "AWS::EC2::InternetGateway", 
    "Properties": { 
    "Tags": [ 
     { 
     "Key": "Name", 
     "Value": "ig001" 
     } 
    ] 
    } 
} 
} 
} 

另外一個好處是能夠在「或過濾器'是價值的組合。 因爲這樣的「AWS :: EC2 :: InternetGateway」或「AWS :: EC2 :: VPC」過濾器應該產生原始文檔。

任何建議或見解將不勝感激。

Tx!

回答

1

@ hek2mgl的建議可能是你的目的是足夠的,但它不完全產生您請求的答案。這是一個非常類似的解決方案。它採用JQ的地圖()和map_values()過濾器,往往是有用的反正的概括:

def mapper(f): 
    if type == "array" then map(f) 
    elif type == "object" then 
    . as $in 
    | reduce keys[] as $key 
     ({}; 
     [$in[$key] | f ] as $value 
     | if $value | length == 0 then . else . + {($key): $value[0]} 
     end) 
    else . 
    end; 

.Resources |= mapper(select(.Type=="AWS::EC2::VPC")) 

使用您的示例輸入:

$ jq -f resources.jq resources.json 
{ 
    "Resources": { 
    "vpc001": { 
     "Type": "AWS::EC2::VPC", 
     "Properties": { 
     "CidrBlock": "10.1.0.0/16", 
     "InstanceTenancy": "default", 
     "EnableDnsSupport": "true", 
     "EnableDnsHostnames": "true" 
     } 
    } 
    } 

正如@ hek2mgl指出,它現在微不足道的指定一個更復雜的選擇標準。 }

+0

嘿!好答案!我在問自己如何產生像你展示的產出,並保持合理的複雜性。意思是保持數據結構不變,只是過濾。我真的很喜歡jq,但是恕我直言,它在很多現實世界的問題上變得複雜。 – hek2mgl

+0

@ hek2mgl - 謝謝! jq當然有改進的餘地。爲什麼不參加https://github.com/stedolan/jq/issues的某些討論,特別是https://github.com/stedolan/jq/issues/1035? – peak

+0

@peak:偉大的通用解決方案,我的問題!仍然在努力把握JQ的全部潛力,但這對我有很大的幫助。 –

0

使用select()功能:

jq '.Resources[]|select(.Type=="AWS::EC2::VPC")' aws.json 

,如果你想通過多條件篩選您可以使用or,像這樣:

jq '.Resources[]|select(.Type=="AWS::EC2::VPC" or .Type=="foo")' aws.json 
+0

謝謝您的回答。我的確和你一樣興奮起來,但是隨着峯值的出現,這樣我就失去了進一步處理所需的信息(對象名稱)。 –

0

這裏是一個解決方案,它使用單獨的函數來選擇所有資源匹配指定條件,爲每個資源傳遞一個{key,value}對。從樣本數據

def condition: 
    .value.Type == "AWS::EC2::VPC" 
; 

{ 
    Resources: .Resources | with_entries(select(condition)) 
} 

輸出:

{ 
    "Resources": { 
    "vpc001": { 
     "Type": "AWS::EC2::VPC", 
     "Properties": { 
     "CidrBlock": "10.1.0.0/16", 
     "InstanceTenancy": "default", 
     "EnableDnsSupport": "true", 
     "EnableDnsHostnames": "true" 
     } 
    } 
    } 
}