Вопрос о [cerberus] для проверки Dict, где некоторые ключи ДОЛЖНЫ присутствовать (и действительны), но другие являются необязательными - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь проверить список тегов, поступивших из aws ec2 describe-instances вызова. Объект Tags глубоко вложен, но вот пример. тип структуры данных, с которой я работаю:


{
    'Reservations': [
        {
            'Groups': [],
            'Instances': [
                {
                    'Tags': [
                        {'Key': 'Namespace', 'Value': 'my-namespace-value'},
                        {
                            'Key': 'some:internal:tag',
                            'Value': 'with.a.value.that.is.not.important'
                        },
                        {'Key': 'SomeInternalThing', 'Value': '["foo","bar"]'},
                        {
                            'Key': 'Namespace Domain',
                            'Value': 'value.namespace.my'
                        },
                        {'Key': 'Stage', 'Value': 'r&d'},
                        {'Key': 'Name', 'Value': 'TheNameOfTheInstanceIAmAskingAmazonAbout'}
                    ]
                }
            ]
        }
    ],
    'ResponseMetadata': {
        'HTTPStatusCode': 200
    }
}

Каждый Tag - это dict с двумя ключами: Name и Value.

Я пытаюсь создать схему проверки, которая требует наличия некоторых Key и игнорирует другие. В приведенном выше примере мне все равно, присутствует ли тег с именем some:internal:tag, мне важно, чтобы присутствовали тег с именами Namespace и Stage.

Правила:

  • В списке Tags будет некоторое неизвестное количество объектов
  • Каждый объект в списке Tags будет идентичен (dict с двумя ключами: Key и Value)

  • Из каждого объекта в списке Tags один Key должен отображаться на Stage (который может иметь Value любой строки) и один Key должен отображаться на Namespace (который может иметь Value любой строки)

Как бы я подошел к этому? Вот что я получил до сих пор:

    _details_schema = {
        ##
        # At the top level, there are only two objects:
        #   - ResponseMetadata; we make sure a 200 is present here
        #   - Reservations; list of all instance types; we'll validate children as needed...
        ##
        #  if we don't  get a HTTP/200, abort!
        'ResponseMetadata': {
            'type': 'dict',
            'schema': {
                'HTTPStatusCode': {
                    'type': 'integer',
                    'allowed': [200]
                }
            }
        },
        # Then the big reservations object
        'Reservations': {
            'type': 'list',
            # And inside of that list will be objects, one of which is the 'Instances' object
            'schema': {
                'type': 'dict',
                'schema': {
                    'Instances': {
                        'type': 'list',
                        'schema': {
                            # Each object in the Instances list is a dict
                            'type': 'dict',
                            'schema':{
                                ##
                                # I have omitted several other schemas here
                                ##
                                # The Tags object is a list of dicts
                                'Tags': {
                                    'type': 'list',
                                    # Each tag will be a dict with Key and Value
                                    # We must check for a minimum set of Keys for the
                                    #   document to be valid
                                    ##
                                    'schema': {
                                        'type': 'dict',
                                        # TODO: How to make sure that Tags.items()['Key'] 
                                        'schema': {
                                            'Key': {
                                                'type': 'string',
                                                'required': True,
                                                'allow_unknown': True,
                                                'allowed': [
                                                    'Stage',
                                                    'Namespace'
                                                ]
                                            },
                                            # We don't care what the value of each Tag is, just as long as it's a string
                                            'Value': {
                                                'type': 'string',
                                            },
                                        }

                                    }
                                }
                            }
                        },
                    }
                }
            }
        }
    }

    _details_vldtr = cerberus.Validator(_details_schema, allow_unknown=True)

    if not _details_vldtr.validate(_api_payload):
         ...


Нужно ли мне создавать собственную функцию валидатора для реализации этой логики c? На данный момент 'allow_unknown': True,, похоже, не работает, потому что я получаю эту ошибку проверки:

Unable to validate event. errors:{'Reservations': [{0: [{'Instances': [{0: [{'Tags': [{0: [{'Key': ['unallowed value Namespace']}], 1: [{'Key': ['unallowed value some:internal:tag']}], 2: [{'Key': ['unallowed value SomeInternalThing']}], 5: [{'Key': ['unallowed value Name']}]}]}]}]}]}]}

Мысли?

...