blob: 690d3810fd16fade3e7852e025636299a9b291de [file] [log] [blame]
Zsolt Harasztid036b7e2016-12-23 15:36:01 -08001#!/usr/bin/env python
2#
3# Copyright 2016 the original author or authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18"""
19Device level CLI commands
20"""
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040021from optparse import make_option
22from cmd2 import Cmd, options
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080023from simplejson import dumps
24
Zsolt Haraszti85f12852016-12-24 08:30:58 -080025from cli.table import print_pb_as_table, print_pb_list_as_table
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080026from cli.utils import print_flows, pb2dict
27from voltha.protos import third_party
28
29_ = third_party
30from voltha.protos import voltha_pb2
Sergio Slobodrian3ba3d562017-04-21 10:07:56 -040031import sys
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040032from voltha.protos.device_pb2 import PmConfigs, PmConfig, PmGroupConfig
33from google.protobuf.json_format import MessageToDict
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080034
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040035# Since proto3 won't send fields that are set to 0/false/"" any object that
36# might have those values set in them needs to be replicated here such that the
Sergio Slobodrian3ba3d562017-04-21 10:07:56 -040037# fields can be adequately
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080038
39class DeviceCli(Cmd):
40
41 def __init__(self, get_channel, device_id):
42 Cmd.__init__(self)
43 self.get_channel = get_channel
44 self.device_id = device_id
45 self.prompt = '(' + self.colorize(
46 self.colorize('device {}'.format(device_id), 'red'), 'bold') + ') '
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040047 self.pm_config_last = None
48 self.pm_config_dirty = False
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080049
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -080050 def cmdloop(self):
51 self._cmdloop()
52
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080053 def get_device(self, depth=0):
54 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
55 res = stub.GetDevice(voltha_pb2.ID(id=self.device_id),
56 metadata=(('get-depth', str(depth)), ))
57 return res
58
Zsolt Haraszti80175202016-12-24 00:17:51 -080059 do_exit = Cmd.do_quit
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080060
Sergio Slobodrian6e9fb692017-03-17 14:46:33 -040061 def do_quit(self, line):
62 if self.pm_config_dirty:
63 self.poutput("Uncommited changes for " + \
64 self.colorize(
65 self.colorize("perf_config,", "blue"),
66 "bold") + " please either " + self.colorize(
67 self.colorize("commit", "blue"), "bold") + \
68 " or " + self.colorize(
69 self.colorize("reset", "blue"), "bold") + \
70 " your changes using " + \
71 self.colorize(
72 self.colorize("perf_config", "blue"), "bold"))
73 return False
74 else:
75 return self._STOP_AND_EXIT
76
Zsolt Haraszti80175202016-12-24 00:17:51 -080077 def do_show(self, line):
78 """Show detailed device information"""
Zsolt Haraszti85f12852016-12-24 08:30:58 -080079 print_pb_as_table('Device {}'.format(self.device_id),
Sergio Slobodriana95f99b2017-03-21 10:22:47 -040080 self.get_device(depth=-1))
Zsolt Haraszti85f12852016-12-24 08:30:58 -080081
82 def do_ports(self, line):
83 """Show ports of device"""
84 device = self.get_device(depth=-1)
85 omit_fields = {
86 }
87 print_pb_list_as_table('Device ports:', device.ports,
88 omit_fields, self.poutput)
Zsolt Haraszti80175202016-12-24 00:17:51 -080089
Sergio Slobodrian3ba3d562017-04-21 10:07:56 -040090 def complete_perf_config(self, text, line, begidx, endidx):
91 sub_cmds = {"show", "set", "commit", "reset"}
92 sub_opts = {"-f", "-e", "-d", "-o"}
93 # Help the interpreter complete the paramters.
94 completions = []
95 if not self.pm_config_last:
96 device = self.get_device(depth=-1)
97 self.pm_config_last = device.pm_configs
98 m_names = [d.name for d in self.pm_config_last.metrics]
99 cur_cmd = line.strip().split(" ")
100 try:
101 if not text and len(cur_cmd) == 1:
102 completions = ("show", "set", "commit", "reset")
103 elif len(cur_cmd) == 2:
104 if "set" == cur_cmd[1]:
105 completions = [d for d in sub_opts]
106 else:
107 completions = [d for d in sub_cmds if d.startswith(text)]
108 elif len(cur_cmd) > 2 and cur_cmd[1] == "set":
109 if cur_cmd[len(cur_cmd)-1] == "-":
110 completions = [list(d)[1] for d in sub_opts]
111 elif cur_cmd[len(cur_cmd)-1] == "-f":
112 completions = ("\255","Please enter a sampling frequency in 10ths of a second")
113 elif cur_cmd[len(cur_cmd)-2] == "-f":
114 completions = [d for d in sub_opts]
115 elif cur_cmd[len(cur_cmd)-1] in {"-e","-d","-o"}:
116 if self.pm_config_last.grouped:
117 pass
118 else:
119 completions = [d.name for d in self.pm_config_last.metrics]
120 elif cur_cmd[len(cur_cmd)-2] in {"-e","-d"}:
121 if text and text not in m_names:
122 completions = [d for d in m_names if d.startswith(text)]
123 else:
124 completions = [d for d in sub_opts]
125 elif cur_cmd[len(cur_cmd)-2] == "-o":
126 if cur_cmd[len(cur_cmd)-1] in [d.name for d in self.pm_config_last.metrics]:
127 completions = ("\255","Please enter a sampling frequency in 10ths of a second")
128 else:
129 completions = [d for d in m_names if d.startswith(text)]
130 elif cur_cmd[len(cur_cmd)-3] == "-o":
131 completions = [d for d in sub_opts]
132 except:
133 e = sys.exc_info()
134 print(e)
135 return completions
136
137
Sergio Slobodrian6e9fb692017-03-17 14:46:33 -0400138 def help_perf_config(self):
139 self.poutput(
140'''
Sergio Slobodrian57979ec2017-03-21 22:32:17 -0400141perf_config [show | set | commit | reset] [-f <default frequency>] [{-e <metric/group
142 name>}] [{-d <metric/group name>}] [{-o <metric/group name> <override
143 frequency>}]
Sergio Slobodrian038bd3c2017-03-22 15:53:25 -0400144
Sergio Slobodrian3fb99b32017-03-22 22:18:21 -0400145show: displays the performance configuration of the device
Sergio Slobodrian57979ec2017-03-21 22:32:17 -0400146set: changes the parameters specified with -e, -d, and -o
147reset: reverts any changes made since the last commit
148commit: commits any changes made which applies them to the device.
149
150-e: enable collection of the specified metric, more than one -e may be
151 specified.
Sergio Slobodrian3fb99b32017-03-22 22:18:21 -0400152-d: disable collection of the specified metric, more than on -d may be
Sergio Slobodrian57979ec2017-03-21 22:32:17 -0400153 specified.
Sergio Slobodrianec6e3912017-04-02 11:46:55 -0400154-o: override the collection frequency of the specified metric, more than one -o
Sergio Slobodrian57979ec2017-03-21 22:32:17 -0400155 may be specified. Note that -o isn't valid unless
Sergio Slobodrian3fb99b32017-03-22 22:18:21 -0400156 frequency_override is set to True for the device.
Sergio Slobodrian57979ec2017-03-21 22:32:17 -0400157
Sergio Slobodrian6e9fb692017-03-17 14:46:33 -0400158Changes made by set are held locally until a commit or reset command is issued.
159A commit command will write the configuration to the device and it takes effect
160immediately. The reset command will undo any changes sinc the start of the
161device session.
162
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400163If grouped is true then the -d, -e and -o commands refer to groups and not
Sergio Slobodrian6e9fb692017-03-17 14:46:33 -0400164individual metrics.
165'''
166 )
167
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400168 @options([
169 make_option('-f', '--default_freq', action="store", dest='default_freq',
170 type='long', default=None),
171 make_option('-e', '--enable', action='append', dest='enable',
172 default=None),
173 make_option('-d', '--disable', action='append', dest='disable',
174 default=None),
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400175 make_option('-o', '--overried', action='append', dest='override',
Sergio Slobodrian6e9fb692017-03-17 14:46:33 -0400176 nargs=2, default=None, type='string'),
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400177 ])
178 def do_perf_config(self, line, opts):
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400179 #print(line)
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400180 """Show and set the performance monitoring configuration of the device"""
181
182 device = self.get_device(depth=-1)
183 if not self.pm_config_last:
184 self.pm_config_last = device.pm_configs
185
186 # Ensure that a valid sub-command was provided
187 if line.strip() not in {"set", "show", "commit", "reset", ""}:
188 self.poutput(self.colorize('Error: ', 'red') + \
189 self.colorize(self.colorize(line.strip(), 'blue'),
190 'bold') + ' is not recognized')
191 return
192
193 # Ensure no options are provided when requesting to view the config
194 if line.strip() == "show" or line.strip() == "":
195 if opts.default_freq or opts.enable or opts.disable:
196 self.poutput(opts.disable)
197 self.poutput(self.colorize('Error: ', 'red') + 'use ' + \
198 self.colorize(self.colorize('"set"', 'blue'),
199 'bold') + ' to change settings')
200 return
201
202 if line.strip() == "set": # Set the supplied values
203 # The defualt frequency
204 if opts.default_freq:
205 self.pm_config_last.default_freq = opts.default_freq
206 self.pm_config_dirty = True
207
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400208 # Field or group visibility
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400209 if self.pm_config_last.grouped:
210 for g in self.pm_config_last.groups:
211 if opts.enable:
212 if g.group_name in opts.enable:
213 g.enabled = True
214 self.pm_config_dirty = True
215 for g in self.pm_config_last.groups:
216 if opts.disable:
217 if g.group_name in opts.disable:
218 g.enabled = False
219 self.pm_config_dirty = True
220 else:
221 for m in self.pm_config_last.metrics:
222 if opts.enable:
223 if m.name in opts.enable:
224 m.enabled = True
225 self.pm_config_dirty = True
226 for m in self.pm_config_last.metrics:
227 if opts.disable:
228 if m.name in opts.disable:
229 m.enabled = False
230 self.pm_config_dirty = True
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400231
232 #Frequency overrides.
233 if opts.override:
234 if self.pm_config_last.freq_override:
235 oo = dict()
236 for o in opts.override:
237 oo[o[0]] = o[1]
238 if self.pm_config_last.grouped:
239 for g in self.pm_config_last.groups:
240 if g.group_name in oo:
241 try:
242 g.group_freq = int(oo[g.group_name])
243 except ValueError:
244 self.poutput(self.colorize('Warning: ',
245 'yellow') + \
246 self.colorize(oo[m.name],
247 'blue') +\
248 " is not an integer... ignored")
249 del oo[g.group_name]
250 self.pm_config_dirty = True
251 else:
252 for m in self.pm_config_last.metrics:
253 if m.name in oo:
254 try:
255 m.sample_freq = int(oo[m.name])
256 except ValueError:
257 self.poutput(self.colorize('Warning: ',
258 'yellow') + \
259 self.colorize(oo[m.name],
260 'blue') +\
261 " is not an integer... ignored")
262 del oo[m.name]
263 self.pm_config_dirty = True
264
265 # If there's anything left the input was typoed
266 if self.pm_config_last.grouped:
267 field = 'group'
268 else:
269 field = 'metric'
270 for o in oo:
271 self.poutput(self.colorize('Warning: ', 'yellow') + \
272 'the parameter' + ' ' + \
273 self.colorize(o, 'blue') + ' is not ' + \
274 'a ' + field + ' name... ignored')
275 if oo:
276 return
277
278 else: # Frequency overrides not enabled
279 self.poutput(self.colorize('Error: ', 'red') + \
280 'Individual overrides are only ' + \
281 'supported if ' + \
282 self.colorize('freq_override', 'blue') + \
283 ' is set to ' + self.colorize('True', 'blue'))
284 return
285 self.poutput("Success")
286 return
287
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400288 elif line.strip() == "commit" and self.pm_config_dirty:
289 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
290 stub.UpdateDevicePmConfigs(self.pm_config_last)
291 self.pm_config_last = self.get_device(depth=-1).pm_configs
292 self.pm_config_dirty = False
293 elif line.strip() == "reset" and self.pm_config_dirty:
294 self.pm_config_last = self.get_device(depth=-1).pm_configs
295 self.pm_config_dirty = False
296
Sergio Slobodrian4236ade2017-03-17 22:01:20 -0400297
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400298 omit_fields = {'groups', 'metrics', 'id'}
299 print_pb_as_table('PM Config:', self.pm_config_last, omit_fields,
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400300 self.poutput,show_nulls=True)
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400301 if self.pm_config_last.grouped:
302 #self.poutput("Supported metric groups:")
303 for g in self.pm_config_last.groups:
304 if self.pm_config_last.freq_override:
305 omit_fields = {'metrics'}
306 else:
307 omit_fields = {'group_freq','metrics'}
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400308 print_pb_as_table('', g, omit_fields, self.poutput,
309 show_nulls=True)
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400310 if g.enabled:
311 state = 'enabled'
312 else:
313 state = 'disabled'
314 print_pb_list_as_table(
Sergio Slobodriana4b89c02017-04-03 12:48:36 -0400315 'Metric group {} is {}'.format(g.group_name,state),
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400316 g.metrics, {'enabled', 'sample_freq'}, self.poutput,
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400317 dividers=100, show_nulls=True)
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400318 else:
319 if self.pm_config_last.freq_override:
320 omit_fields = {}
321 else:
322 omit_fields = {'sample_freq'}
323 print_pb_list_as_table('Supported metrics:', self.pm_config_last.metrics,
Sergio Slobodrian038bd3c2017-03-22 15:53:25 -0400324 omit_fields, self.poutput, dividers=100,
325 show_nulls=True)
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400326
327
Zsolt Haraszti80175202016-12-24 00:17:51 -0800328 def do_flows(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800329 """Show flow table for device"""
330 device = pb2dict(self.get_device(-1))
331 print_flows(
332 'Device',
333 self.device_id,
334 type=device['type'],
335 flows=device['flows']['items'],
336 groups=device['flow_groups']['items']
337 )
338