1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# (c) 2017, Ansible by Red Hat, inc
5#
6# This file is part of Ansible by Red Hat
7#
8# Ansible is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# Ansible is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
20#
21
22
23ANSIBLE_METADATA = {'metadata_version': '1.1',
24                    'status': ['deprecated'],
25                    'supported_by': 'network'}
26
27
28DOCUMENTATION = """
29---
30module: vyos_lldp_interface
31version_added: "2.4"
32author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
33short_description: Manage LLDP interfaces configuration on VyOS network devices
34description:
35  - This module provides declarative management of LLDP interfaces
36    configuration on VyOS network devices.
37deprecated:
38  removed_in: '2.13'
39  alternative: vyos_lldp_interfaces
40  why: Updated modules released with more functionality.
41notes:
42  - Tested against VYOS 1.1.7
43options:
44  name:
45    description:
46      - Name of the interface LLDP should be configured on.
47    type: str
48  aggregate:
49    description: List of interfaces LLDP should be configured on.
50    type: list
51  state:
52    description:
53      - State of the LLDP configuration.
54    default: present
55    choices: ['present', 'absent', 'enabled', 'disabled']
56    type: str
57extends_documentation_fragment: vyos
58"""
59
60EXAMPLES = """
61- name: Enable LLDP on eth1
62  net_lldp_interface:
63    state: present
64
65- name: Enable LLDP on specific interfaces
66  net_lldp_interface:
67    interfaces:
68      - eth1
69      - eth2
70    state: present
71
72- name: Disable LLDP globally
73  net_lldp_interface:
74    state: disabled
75
76- name: Create aggregate of LLDP interface configurations
77  vyos_lldp_interface:
78    aggregate:
79    - name: eth1
80    - name: eth2
81    state: present
82
83- name: Delete aggregate of LLDP interface configurations
84  vyos_lldp_interface:
85    aggregate:
86    - name: eth1
87    - name: eth2
88    state: absent
89"""
90
91RETURN = """
92commands:
93  description: The list of configuration mode commands to send to the device
94  returned: always, except for the platforms that use Netconf transport to manage the device.
95  type: list
96  sample:
97    - set service lldp eth1
98    - set service lldp eth2 disable
99"""
100
101
102from copy import deepcopy
103
104from ansible.module_utils.basic import AnsibleModule
105from ansible.module_utils.network.common.utils import remove_default_spec
106from ansible.module_utils.network.vyos.vyos import get_config, load_config
107from ansible.module_utils.network.vyos.vyos import vyos_argument_spec
108
109
110def search_obj_in_list(name, lst):
111    for o in lst:
112        if o['name'] == name:
113            return o
114
115    return None
116
117
118def map_obj_to_commands(updates, module):
119    commands = list()
120    want, have = updates
121
122    for w in want:
123        name = w['name']
124        state = w['state']
125
126        obj_in_have = search_obj_in_list(name, have)
127
128        if state == 'absent' and obj_in_have:
129            commands.append('delete service lldp interface ' + name)
130        elif state in ('present', 'enabled'):
131            if not obj_in_have:
132                commands.append('set service lldp interface ' + name)
133            elif obj_in_have and obj_in_have['state'] == 'disabled' and state == 'enabled':
134                commands.append('delete service lldp interface ' + name + ' disable')
135        elif state == 'disabled':
136            if not obj_in_have:
137                commands.append('set service lldp interface ' + name)
138                commands.append('set service lldp interface ' + name + ' disable')
139            elif obj_in_have and obj_in_have['state'] != 'disabled':
140                commands.append('set service lldp interface ' + name + ' disable')
141
142    return commands
143
144
145def map_config_to_obj(module):
146    obj = []
147    config = get_config(module).splitlines()
148
149    output = [c for c in config if c.startswith("set service lldp interface")]
150
151    for i in output:
152        splitted_line = i.split()
153
154        if len(splitted_line) > 5:
155            new_obj = {'name': splitted_line[4]}
156
157            if splitted_line[5] == "'disable'":
158                new_obj['state'] = 'disabled'
159        else:
160            new_obj = {'name': splitted_line[4][1:-1]}
161            new_obj['state'] = 'present'
162
163        obj.append(new_obj)
164
165    return obj
166
167
168def map_params_to_obj(module):
169    obj = []
170
171    aggregate = module.params.get('aggregate')
172    if aggregate:
173        for item in aggregate:
174            for key in item:
175                if item.get(key) is None:
176                    item[key] = module.params[key]
177
178            obj.append(item.copy())
179    else:
180        obj.append({'name': module.params['name'], 'state': module.params['state']})
181
182    return obj
183
184
185def main():
186    """ main entry point for module execution
187    """
188    element_spec = dict(
189        name=dict(),
190        state=dict(default='present',
191                   choices=['present', 'absent',
192                            'enabled', 'disabled'])
193    )
194
195    aggregate_spec = deepcopy(element_spec)
196    aggregate_spec['name'] = dict(required=True)
197
198    # remove default in aggregate spec, to handle common arguments
199    remove_default_spec(aggregate_spec)
200
201    argument_spec = dict(
202        aggregate=dict(type='list', elements='dict', options=aggregate_spec),
203    )
204
205    argument_spec.update(element_spec)
206    argument_spec.update(vyos_argument_spec)
207
208    required_one_of = [['name', 'aggregate']]
209    mutually_exclusive = [['name', 'aggregate']]
210
211    module = AnsibleModule(argument_spec=argument_spec,
212                           required_one_of=required_one_of,
213                           mutually_exclusive=mutually_exclusive,
214                           supports_check_mode=True)
215
216    warnings = list()
217
218    result = {'changed': False}
219
220    if warnings:
221        result['warnings'] = warnings
222
223    want = map_params_to_obj(module)
224    have = map_config_to_obj(module)
225
226    commands = map_obj_to_commands((want, have), module)
227    result['commands'] = commands
228
229    if commands:
230        commit = not module.check_mode
231        load_config(module, commands, commit=commit)
232        result['changed'] = True
233
234    module.exit_json(**result)
235
236
237if __name__ == '__main__':
238    main()
239