summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/dellemc/os10/plugins/modules/vlt_validate.py
blob: 2042dfe7719074e0ed8a04296b9c2040ffd812cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)

__copyright__ = "(c) 2020 Dell Inc. or its subsidiaries. All rights reserved."

__metaclass__ = type

DOCUMENTATION = '''
module: vlt_validate
author: "Senthil Kumar Ganesan (@skg-net)"
short_description: Validate the vlt info, raise an error if peer is not in up state
description:

  - Troubleshoot the show vlt info and raise an error if peer is not up.

options:
    show_vlt:
        description:
            - show vlt output
        type: 'list'
        required: True
    show_system_network_summary:
         description:
            - show system summary output
         type: 'list'
         required: True
    intended_vlt_pairs:
         description:
            - intended vlt pair intput to verify with actual
         type: 'list'
         required: True

'''
EXAMPLES = '''
Copy below YAML into a playbook (e.g. play.yml) and run as follows:

#$ ansible-playbook -i inv play.yml
name: show system Configuration
hosts: localhost
connection: local
gather_facts: False
tasks:
 - name: "Get Dell EMC OS10 Show run vlt"
   os10_command:
     commands:
       - command: "show running-configuration vlt | grep vlt-domain"
     provider: "{{ hostvars[item].cli }}"
   with_items: "{{ groups['all'] }}"
   register: show_run_vlt
 - set_fact:
      output_vlt:  "{{ output_vlt|default([])+ [{'host': item.invocation.module_args.provider.host, 'inv_name': item.item,
                                                 'stdout_show_vlt': item.stdout.0}] }}"
   loop: "{{ show_run_vlt.results }}"
 - debug: var=output_vlt
 - name: "Get Dell EMC OS10 Show vlt info"
   os10_command:
     commands:
       - command: "show vlt {{ item.stdout_show_vlt.split()[1] }} | display-xml"
     provider: "{{ hostvars[item.inv_name].cli }}"
   with_items: "{{ output_vlt }}"
   register: show_vlt
 - set_fact:
      vlt_out:  "{{ vlt_out|default([])+ [{'host': item.invocation.module_args.provider.host, 'inv_name': item.item, 'show_vlt_stdout': item.stdout.0}] }}"
   loop: "{{ show_vlt.results }}"
   register: vlt_output
 - name: call lib to convert vlt info from xml to dict format
   base_xml_to_dict:
      cli_responses: "{{ item.show_vlt_stdout }}"
   with_items:
     - "{{ vlt_out }}"
   register: vlt_dict_output
 - name: "Get Dell EMC OS10 Show system"
   import_role:
     name: os10_fabric_summary
   register: show_system_network_summary
 - name: call lib to process
   vlt_validate:
       show_vlt : "{{ vlt_dict_output.results }}"
       show_system_network_summary: "{{ show_system_network_summary.msg.results }}"
       intended_vlt_pairs: "{{ intended_vlt_pairs }}"
   register: show_vlt_info

'''

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from collections import OrderedDict
import traceback


class VltValidation(object):
    def __init__(self):
        self.module = AnsibleModule(argument_spec=self.get_fields())
        self.show_vlt = self.module.params['show_vlt']
        self.show_system_network_summary = self.module.params['show_system_network_summary']
        self.intended_vlt_pairs = self.module.params['intended_vlt_pairs']
        self.exit_msg = OrderedDict()

    def get_fields(self):
        spec_fields = {
            'show_vlt': {
                'type': 'list',
                'required': True
            },
            'show_system_network_summary': {
                'type': 'list',
                'required': True
            },
            'intended_vlt_pairs': {
                'type': 'list',
                'required': True
            }
        }
        return spec_fields

    # get switch inv name from mac
    def get_switch_inv_name_from_mac(self, mac):
        inv_name = None
        for show_system in self.show_system_network_summary:
            if (str.lower(show_system["node-mac"])) == (str.lower(mac)):
                inv_name = show_system.get("inv_name")
                break
        return inv_name

    def validate_vlt_pairs(self, actual_vlt_dict):
        final_out = list()
        intended_vlt_list = self.intended_vlt_pairs
        for intended_vlt in intended_vlt_list:
            intended_primary = intended_vlt.get("primary")
            intended_secondary = intended_vlt.get("secondary")
            actual_vlt = actual_vlt_dict.get(intended_primary)
            temp_dict = {}
            if actual_vlt is not None:
                actual_secondary = actual_vlt.get("secondary")
                secondary_status = actual_vlt.get("secondary_status")
                if actual_secondary is not None and intended_secondary != actual_secondary:
                    temp_dict["error_type"] = "secondary_mismatch"
                    temp_dict["intended_primary"] = intended_primary
                    temp_dict["intended_secondary"] = intended_secondary
                    temp_dict["secondary"] = actual_secondary
                    reason = "config mismatch as {0} is expected, but the actual secondary is {1} " .format(
                        intended_secondary, actual_secondary)
                    temp_dict["possible_reason"] = reason
                    final_out.append(temp_dict)
                else:
                    if actual_secondary is None:
                        temp_dict["intended_primary"] = intended_primary
                        temp_dict["intended_secondary"] = intended_secondary
                        temp_dict["error_type"] = "peer_missing"
                        reason = "peer info is not configured or peer interface is down"
                        temp_dict["possible_reason"] = reason
                        final_out.append(temp_dict)
                    elif intended_secondary == actual_secondary and secondary_status != "up":
                        temp_dict["intended_primary"] = intended_primary
                        temp_dict["intended_secondary"] = intended_secondary
                        temp_dict["secondary"] = actual_secondary
                        temp_dict["error_type"] = "peer_down"
                        reason = "peer interface is down"
                        temp_dict["possible_reason"] = reason
                        final_out.append(temp_dict)
            else:
                temp_dict["intended_primary"] = intended_primary
                temp_dict["intended_secondary"] = intended_secondary
                temp_dict["error_type"] = "vlt_config_missing"
                temp_dict["possible_reason"] = "vlt is not configured"
                final_out.append(temp_dict)
        return final_out

    def parse_vlt_output(self):
        show_vlt_dict = {}
        for show_list in self.show_vlt:
            source_switch = None
            item = show_list.get("item")
            if item is not None:
                inv_info = item.get("inv_name")
                source_switch = inv_info.get("inv_name")
            msg = show_list.get("msg")
            if msg is not None:
                result = msg.get("result")
                for sub_result in result:
                    vlt_dict = {}
                    rpc_reply = sub_result.get("rpc-reply")
                    data = rpc_reply.get("data")
                    if data is not None:
                        topo_oper_data = data.get("topology-oper-data")
                        if topo_oper_data is not None:
                            vlt_domain = topo_oper_data.get("vlt-domain")
                            if vlt_domain is not None:
                                local_info = vlt_domain.get("local-info")
                                if local_info is not None:
                                    local_role = local_info.get("role")
                                    vlt_dict[local_role] = source_switch
                                    local_mac = local_info.get("system-mac")
                                    vlt_dict[local_role + "_mac"] = local_mac
                                peer_info = vlt_domain.get("peer-info")
                                if peer_info is not None:
                                    peer_mac = peer_info.get("system-mac")
                                    peer_switch = self.get_switch_inv_name_from_mac(
                                        peer_mac)
                                    peer_role = peer_info.get("role")
                                    vlt_dict[peer_role] = peer_switch
                                    vlt_dict[peer_role + "_mac"] = peer_mac
                                    peer_status = peer_info.get("peer-status")
                                    vlt_dict[peer_role +
                                             "_status"] = peer_status
                        if bool(vlt_dict):
                            primary_switch = vlt_dict.get("primary")
                            vlt_data = show_vlt_dict.get(primary_switch)
                            if vlt_data is None:
                                # update database specific to primary, it helps
                                # to avoid to skip duplicate data
                                show_vlt_dict[primary_switch] = vlt_dict
        return show_vlt_dict

    def perform_action(self):
        try:
            actual_vlt_dict = self.parse_vlt_output()
            final_out = self.validate_vlt_pairs(actual_vlt_dict)
            self.exit_msg.update({"results": final_out})
            self.module.exit_json(changed=False, msg=self.exit_msg)
        except Exception as e:
            self.module.fail_json(
                msg=to_native(e),
                exception=traceback.format_exc())


def main():
    module_instance = VltValidation()
    module_instance.perform_action()


if __name__ == '__main__':
    main()