Объединение массивов в объект JSON в Ansible

#amazon-web-services #ansible #yaml

#amazon-веб-сервисы #ансибль #ямл #ansible #yaml

Вопрос:

Я хотел бы объединить два объекта JSON из двух приведенных ниже команд, чтобы заменить существующие уведомления S3 на более новые, используя put-bucket-notification-configuration . combine Фильтр, который я использую, в настоящее время выдает мне сообщение об ошибке, в котором говорится, что он ожидает словари.

 ---
- name: Get existing S3 notifications
  command: >
    aws s3api get-bucket-notification-configuration
      --bucket "{{ s3_notification.bucket }}"
      --region "{{ aws_region }}"
  register: existing_s3_notifications
  environment:
    AWS_ACCESS_KEY_ID: "{{ assumed_role.sts_creds.access_key }}"
    AWS_SECRET_ACCESS_KEY: "{{ assumed_role.sts_creds.secret_key }}"
    AWS_SECURITY_TOKEN: "{{ assumed_role.sts_creds.session_token }}"

- name: Combine existing S3 notifications with new notifications
      command: >
        aws s3api put-bucket-notification-configuration
          --bucket "{{ s3_notification.bucket }}"
          --notification-configuration '{{ s3_notification.configuration | to_json | combine(existing_s3_notifications) }}'
          --region "{{ aws_region }}"
      environment:
        AWS_ACCESS_KEY_ID: "{{ assumed_role.sts_creds.access_key }}"
        AWS_SECRET_ACCESS_KEY: "{{ assumed_role.sts_creds.secret_key }}"
        AWS_SECURITY_TOKEN: "{{ assumed_role.sts_creds.session_token }}"
  

Объекты JSON выглядят следующим образом:

 {
"LambdaFunctionConfigurations": [
    {
        "Id": "dev-datamining-wwang-new_product_list",
        "LambdaFunctionArn": "arn:aws:lambda:us-west-2:434815900134:function:dev-datamining-wwang-lambda-update_product_corpus",
        "Events": [
            "s3:ObjectCreated:*"
        ],
        "Filter": {
            "Key": {
                "FilterRules": [
                    {
                        "Name": "Prefix",
                        "Value": "wwang/product_list/"
                    }
                ]
            }
        }
    }
]
}
  

С другим подобным:

 {
"LambdaFunctionConfigurations": [
    {
        "Id": "dev-datamining-alee-new_product_list",
        "LambdaFunctionArn": "arn:aws:lambda:us-west-2:434815900135:function:dev-datamining-alee-lambda-update_product_corpus",
        "Events": [
            "s3:ObjectCreated:*"
        ],
        "Filter": {
            "Key": {
                "FilterRules": [
                    {
                        "Name": "Prefix",
                        "Value": "alee/product_list/"
                    }
                ]
            }
        }
    }
],
"TopicConfigurations": [
    <other stuff>
]
}
  

Я бы хотел, чтобы результат был:

 {
"LambdaFunctionConfigurations": [
    {
        "Id": "dev-datamining-wwang-new_product_list",
        "LambdaFunctionArn": "arn:aws:lambda:us-west-2:434815900134:function:dev-datamining-wwang-lambda-update_product_corpus",
        "Events": [
            "s3:ObjectCreated:*"
        ],
        "Filter": {
            "Key": {
                "FilterRules": [
                    {
                        "Name": "Prefix",
                        "Value": "wwang/product_list/"
                    }
                ]
            }
        }
    },
    {
        "Id": "dev-datamining-alee-new_product_list",
        "LambdaFunctionArn": "arn:aws:lambda:us-west-2:434815900135:function:dev-datamining-alee-lambda-update_product_corpus",
        "Events": [
            "s3:ObjectCreated:*"
        ],
        "Filter": {
            "Key": {
                "FilterRules": [
                    {
                        "Name": "Prefix",
                        "Value": "alee/product_list/"
                    }
                ]
            }
        }
    }
],
"TopicConfigurations": [
    <other stuff>
]
}
  

Как мне объединить эти два объекта, чтобы массивы внутри объектов были объединены вместе?

Ответ №1:

Вам необходимо изучить дополнительный параметр, который combine предлагает вам фильтр:

Фильтр также принимает необязательный recursive=True параметр не только для переопределения ключей в первом хэше, но и для рекурсии во вложенные хэши и объединения их ключей

 {{ {'a':{'foo':1, 'bar':2}, 'b':2} | combine({'a':{'bar':3, 'baz':4}}, recursive=True) }}
  

Это приведет к:

 {'a':{'foo':1, 'bar':3, 'baz':4}, 'b':2}
  

Смотрите: https://docs.ansible.com/ansible/2.9/user_guide/playbooks_filters.html#combining-hashes-dictionaries


Итак, в вашем случае вам действительно нужно сначала объединить два словаря, а затем преобразовать их в JSON:

 - name: Combine existing S3 notifications with new notifications
      command: >
        aws s3api put-bucket-notification-configuration
          --bucket "{{ s3_notification.bucket }}"
          --notification-configuration '{{ s3_notification.configuration | combine(existing_s3_notifications, recursive=True) | to_json }}'
          --region "{{ aws_region }}"
      environment:
        AWS_ACCESS_KEY_ID: "{{ assumed_role.sts_creds.access_key }}"
        AWS_SECRET_ACCESS_KEY: "{{ assumed_role.sts_creds.secret_key }}"
        AWS_SECURITY_TOKEN: "{{ assumed_role.sts_creds.session_token }}"
  

Также имейте в виду, что, если вы уже используете версию 2.10, у вас даже есть еще один дополнительный параметр:

list_merge: является строкой, ее возможными значениями являются replace (по умолчанию), keep , append , prepend , append_rp или prepend_rp . Это изменяет поведение combine , когда хэши для объединения содержат массивы / списки.

Смотрите: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#combining-hashes-dictionaries , содержащий хорошие примеры для каждого значения

Комментарии:

1. К сожалению, мы находимся на 2.8. Есть ли эквивалент list_merge в этой версии?