1# 2# -*- coding: utf-8 -*- 3# Copyright 2019 Red Hat 4# GNU General Public License v3.0+ 5# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6""" 7The junos_lldp class 8It is in this file where the current configuration (as dict) 9is compared to the provided configuration (as dict) and the command set 10necessary to bring the current configuration to it's desired end-state is 11created 12""" 13from __future__ import absolute_import, division, print_function 14__metaclass__ = type 15 16from ansible.module_utils.network.common.cfg.base import ConfigBase 17from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring 18from ansible.module_utils.network.common.utils import to_list 19from ansible.module_utils.network.junos.facts.facts import Facts 20from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node 21 22 23class Lldp_global(ConfigBase): 24 """ 25 The junos_lldp class 26 """ 27 28 gather_subset = [ 29 '!all', 30 '!min', 31 ] 32 33 gather_network_resources = [ 34 'lldp_global', 35 ] 36 37 def __init__(self, module): 38 super(Lldp_global, self).__init__(module) 39 40 def get_lldp_global_facts(self): 41 """ Get the 'facts' (the current configuration) 42 :rtype: A dictionary 43 :returns: The current configuration as a dictionary 44 """ 45 facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) 46 lldp_facts = facts['ansible_network_resources'].get('lldp_global') 47 if not lldp_facts: 48 return {} 49 return lldp_facts 50 51 def execute_module(self): 52 """ Execute the module 53 :rtype: A dictionary 54 :returns: The result from module execution 55 """ 56 result = {'changed': False} 57 58 existing_lldp_global_facts = self.get_lldp_global_facts() 59 config_xmls = self.set_config(existing_lldp_global_facts) 60 61 with locked_config(self._module): 62 for config_xml in to_list(config_xmls): 63 diff = load_config(self._module, config_xml, []) 64 65 commit = not self._module.check_mode 66 if diff: 67 if commit: 68 commit_configuration(self._module) 69 else: 70 discard_changes(self._module) 71 result['changed'] = True 72 73 if self._module._diff: 74 result['diff'] = {'prepared': diff} 75 76 result['commands'] = config_xmls 77 78 changed_lldp_global_facts = self.get_lldp_global_facts() 79 80 result['before'] = existing_lldp_global_facts 81 if result['changed']: 82 result['after'] = changed_lldp_global_facts 83 84 return result 85 86 def set_config(self, existing_lldp_global_facts): 87 """ Collect the configuration from the args passed to the module, 88 collect the current configuration (as a dict from facts) 89 :rtype: A list 90 :returns: the commands necessary to migrate the current configuration 91 to the desired configuration 92 """ 93 want = self._module.params['config'] 94 have = existing_lldp_global_facts 95 resp = self.set_state(want, have) 96 return to_list(resp) 97 98 def set_state(self, want, have): 99 """ Select the appropriate function based on the state provided 100 :param want: the desired configuration as a dictionary 101 :param have: the current configuration as a dictionary 102 :rtype: A list 103 :returns: the list xml configuration necessary to migrate the current configuration 104 to the desired configuration 105 """ 106 root = build_root_xml_node('protocols') 107 state = self._module.params['state'] 108 if state == 'deleted': 109 config_xmls = self._state_deleted(want, have) 110 elif state == 'merged': 111 config_xmls = self._state_merged(want, have) 112 elif state == 'replaced': 113 config_xmls = self._state_replaced(want, have) 114 115 for xml in config_xmls: 116 root.append(xml) 117 return tostring(root) 118 119 def _state_replaced(self, want, have): 120 """ The xml configuration generator when state is merged 121 :rtype: A list 122 :returns: the xml configuration necessary to merge the provided into 123 the current configuration 124 """ 125 lldp_xml = [] 126 lldp_xml.extend(self._state_deleted(want, have)) 127 lldp_xml.extend(self._state_merged(want, have)) 128 129 return lldp_xml 130 131 def _state_merged(self, want, have): 132 """ Select the appropriate function based on the state provided 133 :param want: the desired configuration as a dictionary 134 :param have: the current configuration as a dictionary 135 :rtype: A list 136 :returns: the list xml configuration necessary to migrate the current configuration 137 to the desired configuration 138 """ 139 lldp_xml = [] 140 141 lldp_root = build_root_xml_node('lldp') 142 if want.get('address'): 143 build_child_xml_node(lldp_root, 'management-address', want['address']) 144 if want.get('interval'): 145 build_child_xml_node(lldp_root, 'advertisement-interval', want['interval']) 146 if want.get('transmit_delay'): 147 build_child_xml_node(lldp_root, 'transmit-delay', want['transmit_delay']) 148 if want.get('hold_multiplier'): 149 build_child_xml_node(lldp_root, 'hold-multiplier', want['hold_multiplier']) 150 enable = want.get('enable') 151 if enable is not None: 152 if enable is False: 153 build_child_xml_node(lldp_root, 'disable') 154 else: 155 build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'}) 156 else: 157 build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'}) 158 lldp_xml.append(lldp_root) 159 160 return lldp_xml 161 162 def _state_deleted(self, want, have): 163 """ The command generator when state is deleted 164 :rtype: A list 165 :returns: the commands necessary to remove the current configuration 166 of the provided objects 167 """ 168 lldp_xml = [] 169 170 lldp_root = build_root_xml_node('lldp') 171 build_child_xml_node(lldp_root, 'management-address', None, {'delete': 'delete'}) 172 build_child_xml_node(lldp_root, 'advertisement-interval', None, {'delete': 'delete'}) 173 build_child_xml_node(lldp_root, 'transmit-delay', None, {'delete': 'delete'}) 174 build_child_xml_node(lldp_root, 'hold-multiplier', None, {'delete': 'delete'}) 175 build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'}) 176 lldp_xml.append(lldp_root) 177 return lldp_xml 178