НАЙТИ дубликаты в словаре Ansible - PullRequest
0 голосов
/ 09 сентября 2018

Мне нужно убедиться, что один и тот же порт не используется в двух словарях.

my_dict:
  first:
    redis:
      port: 1234
  second:
    redis:
      port: 1235
  third:
    redis:
      port: 1234

В задании я могу использовать следующее:

- debug:
    msg: '{{ my_dict | dict2items | map(attribute="value.redis.port") | list }}'

Возвращает:

['1234', '1235', '1234']

Что мне нужно, так это какой-то способ отфильтровать только дубликаты. Итак, я получаю:

['1234', '1234']

Возвращается.

По сути, мне нужно проверить, чтобы порты не дублировались, и, если они применяются, выполнить задачу сбоя, которая проверяет и показывает, какие элементы вызывают конфликт.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Большое спасибо за помощь, Мэтью!

Я решил, что факты и т. Д. Слишком уродливы, поэтому решил просто быстро создать плагин для фильтра ... Или, что еще важнее, добавить в mathstuff.py файл.

Добавление:

def duplicate(a):
    if isinstance(a, collections.Hashable):
        c = set(a)
    else:
        s = {}
        c = []

        for x in a:
            if x not in s:
                s[x] = 1
            else:
                if s[x] == 1:
                    c.append(x)
                s[x] += 1
    return c

В основной части документа и добавление:

'duplicate': duplicate,

В к:

class FilterModule(object):
    ''' Ansible math jinja2 filters '''

    def filters(self):
        filters = {

Итак, Jinja2 знает о фильтре.

Я собираюсь сделать запрос на извлечение информации, когда у меня будет время, но если кто-нибудь найдет его в это время, или если вы не хотите / не можете обновить Ansible, то следующее прекрасно работает:

- debug:
    msg: '{{ my_dict | dict2items | map(attribute="value.redis.port") | list | duplicate }}'

Возвращает:

['1234']

Я провел несколько тестов с гораздо большими выборками, и он работает как задумано.

НАСЛАЖДАЙТЕСЬ!

0 голосов
/ 09 сентября 2018

Фильтры, с которыми связан @stacksonstacks, в данном конкретном случае бесполезны, поскольку совокупность портов всегда одинакова, меняется только их число: set([1,2,2,2]) == set([1,2]) всегда True

Итак, что мы действительно хотим, это сгруппировать по порту и искать дочерние элементы длиной более 1. Затем мы можем извлечь имя ключа, который вызвал коллизии, чтобы сообщитьих.

tasks:
- set_fact:
    bogus: >-
      {%- for port_num, dicts in (my_dict | dict2items | groupby('value.redis.port'))
          if (dicts|length) > 1 -%}
      {{ dicts | map(attribute='key') | list }}
      {%- endfor -%}

- debug: var=item
  when: '{{ (bogus | length) > 0 }}'
  with_items: '{{ bogus }}'
...