Open Kilda Java Documentation
dump_state.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 pprint
18 import json
19 from collections import OrderedDict
20 
21 import click
22 from datetime import datetime
23 import prettytable.prettytable as prettytable
24 from prettytable import PrettyTable
25 
26 from kilda.probe.entity.message import create_dump_state
27 from kilda.probe.messaging import send_with_context
28 from kilda.probe.messaging import receive_with_context_async
29 
30 LOG = logging.getLogger(__name__)
31 
32 
33 def print_flow(flow, border):
34  table = PrettyTable(['Property', 'Forward', 'Reverse'], border=border,
35  valign='m')
36  for k, v in flow['forward'].items():
37  if k == 'flowpath':
38 
39  table.add_row(['flowpath:latency_ns', v['latency_ns'],
40  flow['reverse'][k]['latency_ns']])
41  else:
42  table.add_row([k, v, flow['reverse'][k]])
43 
44  table.add_row(['path', print_path(flow['forward'], border),
45  print_path(flow['reverse'], border)])
46 
47  print(table)
48 
49 
50 def print_path(flow, border):
51  path = flow['flowpath']['path']
52  keys = ['switch_id', 'port_no', 'segment_latency', 'seq_id']
53  table = PrettyTable(keys, border=border, vrules=prettytable.NONE,
54  hrules=prettytable.HEADER,
55  padding_width=0)
56 
57  for p in path:
58  table.add_row([p.get(x, None) for x in keys])
59 
60  return table
61 
62 
63 def print_isls_tower(isls, border):
64  table = PrettyTable(['Isl'], border=border)
65  for isl in isls:
66  child_table = PrettyTable(['Property', 'Value'], border=border)
67  for k, v in isl.items():
68  if k == 'path':
69  for p in v:
70  for kk, vv in p.items():
71  child_table.add_row(
72  ['path:{}:{}'.format(p['seq_id'], kk), vv])
73  else:
74  child_table.add_row([k, v])
75  table.add_row([child_table])
76  print(table)
77 
78 
79 def print_isls(isls, border):
80  if not isls:
81  return
82  columns = set()
83  raw = []
84  for isl in isls:
85  d = isl.copy()
86  if 'path' in d:
87  for p in d['path']:
88  for kk, vv in p.items():
89  d['p{}:{}'.format(p['seq_id'], kk)] = vv
90  raw.append(d)
91  columns.update(d.keys())
92 
93  columns -= {'id', 'path', 'message_type', 'p0:segment_latency',
94  'created_in_cache', 'updated_in_cache', 'clazz'}
95 
96  sorted_columns = ['id'] + sorted(list(columns)) + ['created_in_cache',
97  'updated_in_cache']
98 
99  sorted_columns_with_names = OrderedDict(
100  zip(sorted_columns, sorted_columns))
101 
102  sorted_columns_with_names.update({'available_bandwidth': 'av/bw',
103  'created_in_cache': 'created',
104  'updated_in_cache': 'updated',
105  'latency_ns': 'lat'})
106 
107  table = PrettyTable(sorted_columns_with_names.values(),
108  border=border,
109  sortby='id',
110  vrules=prettytable.FRAME,
111  hrules=prettytable.FRAME)
112 
114 
115  for d in raw:
116  table.add_row([d.get(x, '-') for x in sorted_columns_with_names.keys()])
117 
118  print(table)
119 
120 
122  for r in data:
123  for time_field in ['created_in_cache', 'updated_in_cache']:
124  if time_field in r:
125  r[time_field] = datetime.utcfromtimestamp(r[time_field])
126 
127 
128 def print_switches(switches, border):
129  if not switches:
130  return
131 
132  columns = set(switches[0].keys())
133  columns -= {'switch_id', 'created_in_cache', 'updated_in_cache'}
134 
135  sorted_columns = ['switch_id'] + sorted(columns) + ['created_in_cache',
136  'updated_in_cache']
137 
138  sorted_columns_with_names = OrderedDict(
139  zip(sorted_columns, sorted_columns))
140 
141  sorted_columns_with_names.update({'created_in_cache': 'created',
142  'updated_in_cache': 'updated'})
143 
144  table = PrettyTable(sorted_columns_with_names.values(),
145  border=border,
146  sortby='switch_id',
147  vrules=prettytable.FRAME,
148  hrules=prettytable.FRAME)
149 
150  convert_timefied_to_human(switches)
151 
152  for s in switches:
153  table.add_row([s[x] for x in sorted_columns_with_names.keys()])
154 
155  print(table)
156 
157 
158 def print_flows_from_payload(payload, border):
159  flows = payload['state']['flow']['flows']
160  if flows:
161  print('+----------')
162  print('| Flows')
163  for flow in flows:
164  print_flow(flow, border)
165 
166 
167 def cache_bolt_print_table(payload, border):
168  print_flows_from_payload(payload, border)
169 
170  isls = payload['state']['network']['isls']
171  if isls:
172  print('+----------')
173  print('| Isls')
174  print_isls(isls, border)
175 
176  switches = payload['state']['network']['switches']
177  if switches:
178  print('+----------')
179  print('| Switches')
180  print_switches(switches, border)
181 
182 
183 def crud_bolt_print_table(payload, border):
184  print_flows_from_payload(payload, border)
185 
186 
187 def print_table(records, border):
188  for record in records:
189  data = json.loads(record.value)
190  payload = data['payload']
191  LOG.debug(pprint.pformat(data))
192  table = PrettyTable(['Topology', 'Component', 'Task ID'],
193  border=border)
194  table.add_row(
195  [payload['topology'], payload['component'], payload['task_id']])
196 
197  print(table)
198 
199  clazz = payload['state']['clazz']
200  if clazz == 'org.openkilda.messaging.ctrl.state.CacheBoltState':
201  cache_bolt_print_table(payload, border)
202  elif clazz == 'org.openkilda.messaging.ctrl.state.CrudBoltState':
203  crud_bolt_print_table(payload, border)
204  else:
205  print(pprint.pformat(payload['state']))
206 
207  print('\n')
208 
209 
210 @click.command(name='dump-state')
211 @click.argument('destination')
212 @click.option('--border/--no-border', default=True)
213 @click.option('--table', 'output_type', flag_value='table', default=True)
214 @click.option('--json', 'output_type', flag_value='json')
215 @click.option('--allow-dangerous-operation/--prevent-dangerous-operation', default=False)
216 @click.pass_obj
217 def dump_state_command(ctx, destination, border, output_type, allow_dangerous_operation):
218 
219  if not allow_dangerous_operation:
220  click.secho("DON'T RUN ON PRODUCTION MAY CAUSE OVERSIZED KAFKA MESSAGE",
221  blink=True, bold=True)
222  return
223 
224  message = create_dump_state(ctx.correlation_id, destination=destination)
225  LOG.debug('command = {}'.format(message.serialize()))
226 
227  with receive_with_context_async(ctx) as records:
228  send_with_context(ctx, message.serialize())
229 
230  if output_type == 'table':
231  print_table(records, border)
232  elif output_type == 'json':
233  for record in records:
234  data = json.loads(record.value)
235  print(pprint.pformat(data))
def print_table(records, border)
Definition: dump_state.py:187
def print_flow(flow, border)
Definition: dump_state.py:33
def print_isls(isls, border)
Definition: dump_state.py:79
def print_switches(switches, border)
Definition: dump_state.py:128
def send_with_context(context, message)
Definition: messaging.py:28
def create_dump_state(correlation_id, destination)
Definition: message.py:79
def receive_with_context_async(context, expected_count=None)
Definition: messaging.py:43
def cache_bolt_print_table(payload, border)
Definition: dump_state.py:167
def print_path(flow, border)
Definition: dump_state.py:50
def print_isls_tower(isls, border)
Definition: dump_state.py:63
def crud_bolt_print_table(payload, border)
Definition: dump_state.py:183
def print_flows_from_payload(payload, border)
Definition: dump_state.py:158
def dump_state_command(ctx, destination, border, output_type, allow_dangerous_operation)
Definition: dump_state.py:217