From a17083ea84217e3d894e8bb1020b2a13d3dcc991 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sun, 23 Feb 2025 15:26:57 +0100 Subject: [PATCH] [PR #9657/2b6f4ba2 backport][stable-10] lldp: Handling attributes that are defined multiple times (#9799) lldp: Handling attributes that are defined multiple times (#9657) * lldp: Ignoring values for keys already defined This fixes crashes when the lldpctl output has lines for unknown tlvs that redefine a key in the middle of the nested dict data structure. * lldp: handling attributes that are defined multiple times - Fix crash caused by certain lldpctl output where an attribute is defined as branch and leaf - Adds multivalues parameter to control behavior when lldpctl outputs an attribute multiple times * lldp: using isinstance instead of type * Link to Github PR Apply suggestions from code review Co-authored-by: Felix Fontein * lldp: only push value to subkey in multivalues mode To provide backwards compatibility values that are defined as a attribute and also as a path element are only pushed to the 'value' subkey when using the new multivalues mode. --------- Co-authored-by: Felix Fontein (cherry picked from commit 2b6f4ba2992f9c002a33e00d2618842146dc80ce) Co-authored-by: Julian Wecke --- ...ling-attributes-defined-multiple-times.yml | 4 ++ plugins/modules/lldp.py | 38 ++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/9657-lldp-handling-attributes-defined-multiple-times.yml diff --git a/changelogs/fragments/9657-lldp-handling-attributes-defined-multiple-times.yml b/changelogs/fragments/9657-lldp-handling-attributes-defined-multiple-times.yml new file mode 100644 index 0000000000..364013afc8 --- /dev/null +++ b/changelogs/fragments/9657-lldp-handling-attributes-defined-multiple-times.yml @@ -0,0 +1,4 @@ +bugfixes: + - lldp - fix crash caused by certain lldpctl output where an attribute is defined as branch and leaf (https://github.com/ansible-collections/community.general/pull/9657). +minor_changes: + - lldp - adds ``multivalues`` parameter to control behavior when lldpctl outputs an attribute multiple times (https://github.com/ansible-collections/community.general/pull/9657). diff --git a/plugins/modules/lldp.py b/plugins/modules/lldp.py index baefb09d91..7f4a820257 100644 --- a/plugins/modules/lldp.py +++ b/plugins/modules/lldp.py @@ -22,7 +22,12 @@ attributes: support: none diff_mode: support: none -options: {} +options: + multivalues: + description: If lldpctl outputs an attribute multiple time represent all values as a list. + required: false + type: bool + default: false author: "Andy Hill (@andyhky)" notes: - Requires C(lldpd) running and LLDP enabled on switches. @@ -53,26 +58,49 @@ def gather_lldp(module): if output: output_dict = {} current_dict = {} - lldp_entries = output.split("\n") + lldp_entries = output.strip().split("\n") + final = "" for entry in lldp_entries: if entry.startswith('lldp'): path, value = entry.strip().split("=", 1) path = path.split(".") path_components, final = path[:-1], path[-1] + elif final in current_dict and isinstance(current_dict[final], str): + current_dict[final] += '\n' + entry + continue + elif final in current_dict and isinstance(current_dict[final], list): + current_dict[final][-1] += '\n' + entry + continue else: - value = current_dict[final] + '\n' + entry + continue current_dict = output_dict for path_component in path_components: current_dict[path_component] = current_dict.get(path_component, {}) + if not isinstance(current_dict[path_component], dict): + current_dict[path_component] = {'value': current_dict[path_component]} current_dict = current_dict[path_component] - current_dict[final] = value + + if final in current_dict and isinstance(current_dict[final], dict) and module.params['multivalues']: + current_dict = current_dict[final] + final = 'value' + + if final not in current_dict or not module.params['multivalues']: + current_dict[final] = value + elif isinstance(current_dict[final], str): + current_dict[final] = [current_dict[final], value] + elif isinstance(current_dict[final], list): + current_dict[final].append(value) + return output_dict def main(): - module = AnsibleModule({}) + module_args = dict( + multivalues=dict(type='bool', required=False, default=False) + ) + module = AnsibleModule(module_args) lldp_output = gather_lldp(module) try: