问题
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