In Ansible/Jinja is there a way to regex_replace strings with integers using a dictionary of k:v pairs?

廉价感情. 提交于 2020-05-17 03:53:07

问题


NOTE: Original question expanded on here: Is there a way in Ansible to replace a dictionary value based on k:v lookup to another dictionary?

I have 3 dictionaries, the first 2 are k:v with string:integer type values; My 3rd dictionary is a k:v of string:string which I want to loop through first with dict #1 and to replace the k with the k:v and then the same with dict #2 but replacing v with k:v.

"dict_1": {
    "office-core01": 85,
    "office-core02": 86,
    "office-fw01": 87,
    "office-fw02": 88,
    "office-server-sw01": 91,
    "office-vpn01": 92,
    "office-vpn02": 93
}
"dict_2": {
    "con1": 129,
    "con2": 130,
    "con3": 131,
    "con4": 132,
    "con5": 133,
    "con6": 134,
    "con7": 135,
    "con8": 136,
    "con9": 137
}
"dict_3": {
    "office-core01": "con1", 
    "office-core02": "con2", 
    "office-fw01": "con3", 
    "office-fw02": "con4", 
    "office-server-sw01": "con7", 
    "office-vpn01": "con5", 
    "office-vpn02": "con6"
}

In the end I need a dictionary of k:v pairs of integers; For example in the first iteration I need the hostnames/keys (office-core01) in dict_3 replaced with value from dict_1 (85) and then the 2nd run to replace the ports/values (con1) replaced with key from dict_2 (129) however using code supplied by Vladimir in original question complains about object of type 'int' has no len().

Include task (console-portid.yml):

---
  - name: Replace Console Hostname ID
    set_fact:
      port_mapping: "{{ port_mapping | difference([item]) +
                        [dict(my_value | zip(my_keys))] }}"
    vars:
      my_key: "{{ item.keys() | list }}"
      my_value: "{{ item.values() | list }}"
      my_keys: "{{ my_key | map('regex_replace', port_id.key, port_id.value) | list }}"
    loop: "{{ dict_3 | dict2items }}"

Invocation:

- name: Replace Device Console Ports ID
  include_tasks: console-portid.yml
  loop: "{{ dict_1 | dict2items }}"
  loop_control:
    loop_var: port_id

回答1:


Q: "I want to turn office-core01: con1 into 85: 129"

A: The task below does the job

    - set_fact:
        dict_3a: "{{ dict_3a|default({})|
                     combine({dict_1[item.key]: dict_2[item.value]}) }}"
      loop: "{{ dict_3|dict2items }}"
    - debug:
        var: dict_3a

give

    "dict_3a": {
        "85": 129, 
        "86": 130, 
        "87": 131, 
        "88": 132, 
        "91": 135, 
        "92": 133, 
        "93": 134
    }

Q: "Is there a reason key is string and value still integer?"

A: Internal type of the variable is preserved. The variables evaluate to strings unless configured by DEFAULT_JINJA2_NATIVE. Quoting "This option preserves variable types during template operations. This requires Jinja2 >= 2.10."


Q: "Is there a reason key is string and value still integer? Does key always have to be a string?"

A: There are no restrictions on the keys. Quoting from 3.2.1.1. Nodes

"A YAML node represents a single native data structure. Such nodes have content of one of three kinds: scalar, sequence, or mapping. In addition, each node has a tag which serves to restrict the set of possible values the content can have."

"Mapping: The content of a mapping node is an unordered set of key: value node pairs, with the restriction that each of the keys is unique. YAML places no further restrictions on the nodes. In particular, keys may be arbitrary n odes, the same node may be used as the value of several key: value pairs, and a mapping could even contain itself as a key or a value (directly or indirectly)."




回答2:


---
- hosts: localhost
  gather_facts: no
  tasks:
  - name: Loop over dict_3
    debug:
      msg: "{{ item.key }}: {{ item.value }}"
    with_items: "{{ lookup('dict', dict_3) }}"

  - name: Loop over dict_3 with replacements
    debug:
      msg: "{{ dict_1[item.key] }}: {{ dict_2[item.value] }}"
    with_items: "{{ lookup('dict', dict_3) }}"

  - name: Create new dictionary
    set_fact:
      dict_4: "{{ dict_4|default({}) | combine( {dict_1[item.key]: dict_2[item.value]} ) }}"
    with_items: "{{ lookup('dict', dict_3) }}"

  - name: Show dict_4
    debug:
      var: dict_4


来源:https://stackoverflow.com/questions/60671583/in-ansible-jinja-is-there-a-way-to-regex-replace-strings-with-integers-using-a-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!