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()
|