json 地形-/usr/本地/bin/jq:参数列表太长

kx1ctssn  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(167)

这是一个以前被问过的问题的变体。
我在Terraform中使用外部数据源,请求它提供AWS都柏林中的卷快照列表,并在模板文件中使用JQ提取快照ID。

data "external" "volsnapshot_ids" {

  program    = [

    "bash",

    "-c",

    templatefile("cli.tftpl", {input_string = "aws ec2 describe-snapshots --region=eu-west-1", top = "Snapshots", next = "| .SnapshotId"})]

}

它使用以下模板文件:

#!/bin/bash

set -e

OUTPUT=$(${input_string} | jq  -r -c '.${top}[] ${next}' | jq -R -s -c 'split("\n")' | jq '.[:-1]')

jq -n -c --arg output "$OUTPUT" '{"output":$output}'

JQ的基本CLI命令如下所示:

aws ec2 describe-snapshots --region=eu-west-1 | jq  -r -c '.Snapshots[] | .SnapshotId' | jq -R -s -c 'split("\n")' | jq '.[:-1]' | wc -l

它返回大量快照ID。
但是当我在Terraform中运行它时,它出错了:

Error: External Program Execution Failed

│ 

│   with data.external.volsnapshot_ids,

│   on data.tf line 304, in data "external" "volsnapshot_ids":

│  304:   program    = [

│  305:     "bash",

│  306:     "-c", 

│  307:     templatefile("cli.tftpl", {input_string = "aws ec2 describe-snapshots --region=eu-west-1", top = "Snapshots", next = "| .SnapshotId"})]

│ 

│ The data source received an unexpected error while attempting to execute

│ the program.

│ 

│ Program: /bin/bash

│ Error Message: bash: line 6: /usr/local/bin/jq: Argument list too long

│ 

│ State: exit status 1

我认为这是返回的数据集的大小,因为它适用于快照ID较少的区域-伦敦适用。
从尺寸上看,这是伦敦:

aws ec2 describe-snapshots --region=eu-west-2 | jq  -r -c '.Snapshots[] | .SnapshotId' | jq -R -s -c 'split("\n")' | jq '.[:-1]' | wc -l
20000

这是都柏林

aws ec2 describe-snapshots --region=eu-west-1 | jq  -r -c '.Snapshots[] | .SnapshotId' | jq -R -s -c 'split("\n")' | jq '.[:-1]' | wc -l
42500

有没有办法修复我的模板文件中的JQ,使它可以处理大的JSON文件?

aydmsdu9

aydmsdu91#

我不建议在TF数据源中使用命令。可能很难调试。有一个data_source用于EBS快照。
至于你在模板中的命令,为了调试它,你需要模拟相同的环境。例如,不要按原样运行,而是尝试重复你在模板中的内容,比如bash -c等等。你也可以add output to see the template rendered来看看是否有任何问题。

a64a0gku

a64a0gku2#

滚动到答案底部。
不要将值作为参数提供,而是直接通过标准输入:

aws ... \
  | jq -rc '.${top}[] ${next}' \
  | jq -Rsc './"\n"' \
  | jq -c '.[:-1]'
  | jq -Rc '{output:.}'

请注意,您可能可以将大多数单独的jq调用合并到单个jq程序中。
这种jq调用的管道是一个巨大的,* 巨大的 * 过于复杂的非解决方案。为什么在字符串和JSON对象之间来回转换,再次解析这些字符串,而jq已经可以直接处理数据了?

aws ... | jq -c '{ output: .Snapshots | map(.SnapshotId) | tostring }'

输出示例:

{"output":"[\"snap-cafebabe\",\"snap-deadbeef\",\"snap-0123abcd\"]"}

如果必须使用变量:

top=Snapshots
next=SnapshotId
aws ... | jq --arg top "$top" --arg next "$next" -c '{ output: .[$top] | map(.[$next]) | tostring }'

或者.[$top] | map(.[$next]) | tostring | { output: . }或者.[$top] | map(.[$next]) | { output: tostring }
即使您想要或需要将多个jq调用串在一起,如果您已经拥有流形式的结构完美的JSON项,那么使用原始输入(-R)并尝试解析它也没有什么意义。
如果您想通过多个步骤来完成,但始终停留在JSON领域(而不是在结构化JSON和非结构化文本之间打乒乓球),则会出现以下情况:

top=Snapshots
next=SnapshotId
aws ... \
  | jq --arg top "$top" --arg next "$next" '.[$top][][$next]' \
  | jq -sc '{ output: tostring }'

或同等产品:

top=Snapshots
next=SnapshotId
aws ... \
  | jq --arg top "$top" --arg next "$next" '.[$top] | map(.[$next])' \
  | jq -c '{ output: tostring }'

相关问题