Open Kilda Java Documentation
switch_port_status.py
Go to the documentation of this file.
1 # Copyright 2017 Telstra Open Source
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 
16 import logging
17 import json
18 import requests
19 import traceback
20 import pprint
21 
22 import click
23 
24 from kilda.probe.entity.message import create_dump_state_by_switch
25 
26 from kilda.probe.messaging import receive_with_context_async, send_with_context
27 from py2neo import Graph
28 
29 from prettytable import PrettyTable
30 
31 LOG = logging.getLogger(__name__)
32 
33 
34 def print_table(records):
35  table = PrettyTable(
36  ['PORT', 'FL-PORT', 'FL-LINK', 'NEO4J-SRC', 'NEO4J-DST',
37  'NEO4J-REMOTE', 'WFM-ISL-FOUND', 'WFM-ISL-STATUS', 'RECEIVE-DROPPED',
38  'RECEIVE-PACKETS', 'TRANSMIT-PACKETS'], align='l')
39  for port_id, v in records.items():
40  table.add_row(
41  [port_id,
42  v.get('FL_PORT', '-'),
43  v.get('FL_LINK', '-'),
44  v.get('NEO4J_SRC', '-'),
45  v.get('NEO4J_DST', '-'),
46  v.get('REMOTE', '-'),
47  v.get('WFM_ISL_FOUND', '-'),
48  v.get('WFM_ISL_STATUS', '-'),
49  v.get('RECEIVE_DROPPED', '-'),
50  v.get('RECEIVE_PACKETS', '-'),
51  v.get('TRANSMIT_PACKETS', '-')
52  ])
53  print(table)
54 
55 
56 def fl_get_ports_stats_for_switch(ctx, switch_id, debug):
57  url = "{}/wm/core/switch/{}/port/json".format(ctx.fl_host, switch_id)
58  result = requests.get(url)
59  result.raise_for_status()
60 
61  result_data = result.json()
62  if debug:
63  print(result)
64  pprint.pprint(result_data)
65 
66  ports = result_data['port_reply'][0]['port']
67 
68  return {int(x['port_number']): {'RECEIVE_DROPPED': x['receive_dropped'],
69  'RECEIVE_PACKETS': x['receive_packets'],
70  'TRANSMIT_PACKETS': x['transmit_packets'],
71  } for x in
72  ports if x['port_number'].isdigit()}
73 
74 
75 def fl_get_ports_for_switch(ctx, switch_id, debug):
76  url = "{}/wm/core/switch/{}/port-desc/json".format(ctx.fl_host, switch_id)
77  result = requests.get(url)
78  result.raise_for_status()
79 
80  if debug:
81  print(result)
82  print(result.json())
83 
84  result_data = result.json()
85 
86  if 'port_desc' in result_data:
87  def get_status(sw):
88 
89  r = {'FL_PORT': 'PORT_UP',
90  'FL_LINK': 'LINK_UP'}
91 
92  if 'PORT_DOWN' in sw['config']:
93  r['FL_PORT'] = 'PORT_DOWN'
94  if 'LINK_DOWN' in sw['state']:
95  r['FL_LINK'] = 'LINK_DOWN'
96 
97  return r
98 
99  return {int(x['port_number']): get_status(x) for x in
100  result.json()['port_desc'] if x['port_number'].isdigit()}
101 
102  return []
103 
104 
105 def neo4g_ports_for_switch(ctx, switch_id):
106  query = 'MATCH ()-[r:isl]->() WHERE r.src_switch = "{}" OR r.dst_switch ' \
107  '= "{}" RETURN r'.format(switch_id, switch_id)
108 
109  graph = Graph("http://{}:{}@{}:7474/db/data/".format(
110  ctx.neo4j_user,
111  ctx.neo4j_pass,
112  ctx.neo4j_host))
113 
114  result = graph.run(query).data()
115 
116  def get_status(link):
117  if link['src_switch'] == switch_id:
118  return {'NEO4J_SRC': link['status']}
119  return {'NEO4J_DST': link['status']}
120 
121  def get_port_from_link(link):
122  if link['src_switch'] == switch_id:
123  return link['src_port']
124  return link['dst_port']
125 
126  retval = {}
127 
128  for x in result:
129  x = x['r']
130  port_id = int(get_port_from_link(x))
131 
132  if port_id not in retval:
133  retval[port_id] = {}
134 
135  retval[port_id].update(get_status(x))
136 
137  if x['src_switch'] == switch_id:
138  retval[port_id]['REMOTE'] = '{}-{}'.format(x['dst_switch'],
139  x['dst_port'])
140  return retval
141 
142 
143 def wfm_ports_for_switch(ctx, switch_id):
144  message = create_dump_state_by_switch(ctx.correlation_id,
145  'wfm/kilda.topo.disco-bolt',
146  switch_id)
147 
148  with receive_with_context_async(ctx, 1) as records:
149  send_with_context(ctx, message.serialize())
150 
151  if not records:
152  LOG.error("wfm/kilda.topo.disco-bolt NO RESPONSE")
153 
154  retval = {}
155 
156  for record in records:
157  data = json.loads(record.value)
158  payload = data['payload']
159 
160  for port in payload['state']['discovery']:
161 
162  if port['consecutive_success'] == 0:
163  status = 'DOWN'
164  elif port['consecutive_failure'] == 0:
165  status = 'UP'
166  else:
167  status = 'N/A'
168 
169  retval[int(port['port_id'])] = {
170  'WFM_ISL_FOUND': 'FOUND' if port['found_isl'] else 'NOT FOUND',
171  'WFM_ISL_STATUS': '{}'.format(status)
172  }
173 
174  return retval
175 
176 
177 @click.command(name='switch-port-status')
178 @click.argument('switch-id')
179 @click.pass_obj
180 def switch_port_status_command(ctx, switch_id):
181  try:
182  fl_results = fl_get_ports_for_switch(ctx, switch_id, ctx.debug)
183  except Exception as ex:
184  traceback.print_exc()
185  fl_results = {}
186 
187  try:
188  fl_port_stats_results = fl_get_ports_stats_for_switch(ctx, switch_id,
189  ctx.debug)
190  except Exception as ex:
191  traceback.print_exc()
192  fl_port_stats_results = {}
193 
194  try:
195  wfm_results = wfm_ports_for_switch(ctx, switch_id)
196  wfm_results_no_records = len(wfm_results) == 0
197  except Exception as ex:
198  traceback.print_exc()
199  wfm_results = {}
200  wfm_results_no_records = False
201 
202  try:
203  neo4j_results = neo4g_ports_for_switch(ctx, switch_id)
204  except Exception as ex:
205  traceback.print_exc()
206  neo4j_results = {}
207 
208  port_ids = set(list(fl_results.keys()) +
209  list(neo4j_results.keys()) +
210  list(wfm_results.keys()) +
211  list(fl_port_stats_results.keys())
212  )
213 
214  results = {}
215 
216  if wfm_results_no_records:
217  wfm_results = {port_id: {'WFM_ISL_FOUND': 'NO DATA'} for port_id in
218  port_ids}
219 
220  for port in port_ids:
221  results[port] = {}
222  results[port].update(fl_results.get(port, {}))
223  results[port].update(neo4j_results.get(port, {}))
224  results[port].update(wfm_results.get(port, {}))
225  results[port].update(fl_port_stats_results.get(port, {}))
226 
227  print_table(results)
def create_dump_state_by_switch(correlation_id, destination, switch)
Definition: message.py:83
def send_with_context(context, message)
Definition: messaging.py:28
def receive_with_context_async(context, expected_count=None)
Definition: messaging.py:43
def fl_get_ports_stats_for_switch(ctx, switch_id, debug)
def fl_get_ports_for_switch(ctx, switch_id, debug)