Фильтрация ресурсов стека облачной информации с помощью JQ

Я пытаюсь написать JQ-фильтр для фильтрации определенных ресурсов из шаблона облачной информации AWS на основе свойств ресурса.

Например, при запуске из следующего (сокращенного) шаблона облачной информации:

{
"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!


person Kurt Gielen    schedule 05.12.2015    source источник


Ответы (4)


Предложение @hek2mgl может быть достаточным для ваших целей, но оно не совсем дает ответ, который вы запрашивали. Вот одно очень похожее решение. Он использует обобщение фильтров jq map () и 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, теперь просто указать более сложный критерий выбора. }

person peak    schedule 05.12.2015
comment
Привет! Хороший ответ! Я спрашивал себя, как получить такой результат, как вы показали, и при этом сохранить разумную сложность. Это означает сохранить структуру данных как есть, просто отфильтруйте. Мне очень нравится jq, но ИМХО он становится слишком сложным для многих реальных проблем. - person hek2mgl; 05.12.2015
comment
@ hek2mgl - Спасибо! jq, безусловно, можно улучшить. Почему бы не принять участие в обсуждении на github.com/stedolan/jq/issues и особенно github.com/stedolan/jq/issues/1035? - person peak; 05.12.2015
comment
@peak: отличное универсальное решение моей проблемы! Я все еще пытаюсь понять весь потенциал JQ, но это меня немного помогает. - person Kurt Gielen; 05.12.2015

Используйте функцию select():

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

Вы можете использовать or, если хотите фильтровать по нескольким условиям, например:

jq '.Resources[]|select(.Type=="AWS::EC2::VPC" or .Type=="foo")' aws.json
person hek2mgl    schedule 05.12.2015
comment
спасибо за Ваш ответ. Я достиг той же точки, что и вы, но, как показывает пик, я теряю информацию (имена объектов), необходимую для дальнейшей обработки. - person Kurt Gielen; 05.12.2015

Используйте параметр aws cli --query. Полностью устраняет необходимость в jq. http://docs.aws.amazon.com/cli/latest/userguide/controlling-output.html#controlling-output-filter.

person Bruce Edge    schedule 28.09.2016

Вот решение, которое использует отдельную функцию для выбора всех ресурсов, соответствующих указанному условию, которому передается пара {ключ, значение} для каждого ресурса.

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"
      }
    }
  }
}
person jq170727    schedule 28.08.2017