blob: 25ad72bbeeadf4509774318bb27184eeb5501b13 [file] [log] [blame]
khenaidoofdbad6e2018-11-06 22:26:38 -05001#!/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"""
21from optparse import make_option
22from cmd2 import Cmd, options
23from simplejson import dumps
24
25from table import print_pb_as_table, print_pb_list_as_table
26from utils import print_flows, pb2dict, enum2name
khenaidoofdbad6e2018-11-06 22:26:38 -050027
Arun Aroraed4b7602019-04-02 18:42:37 +000028from voltha_protos import voltha_pb2, common_pb2
khenaidoofdbad6e2018-11-06 22:26:38 -050029import sys
30import json
31from google.protobuf.json_format import MessageToDict
32
33# Since proto3 won't send fields that are set to 0/false/"" any object that
34# might have those values set in them needs to be replicated here such that the
35# fields can be adequately
36
37
38class DeviceCli(Cmd):
39
40 def __init__(self, device_id, get_stub):
41 Cmd.__init__(self)
42 self.get_stub = get_stub
43 self.device_id = device_id
44 self.prompt = '(' + self.colorize(
45 self.colorize('device {}'.format(device_id), 'red'), 'bold') + ') '
46 self.pm_config_last = None
47 self.pm_config_dirty = False
48
49 def cmdloop(self):
50 self._cmdloop()
51
52 def get_device(self, depth=0):
53 stub = self.get_stub()
54 res = stub.GetDevice(voltha_pb2.ID(id=self.device_id),
55 metadata=(('get-depth', str(depth)), ))
56 return res
57
58 do_exit = Cmd.do_quit
59
60 def do_quit(self, line):
61 if self.pm_config_dirty:
62 self.poutput("Uncommited changes for " + \
63 self.colorize(
64 self.colorize("perf_config,", "blue"),
65 "bold") + " please either " + self.colorize(
66 self.colorize("commit", "blue"), "bold") + \
67 " or " + self.colorize(
68 self.colorize("reset", "blue"), "bold") + \
69 " your changes using " + \
70 self.colorize(
71 self.colorize("perf_config", "blue"), "bold"))
72 return False
73 else:
74 return self._STOP_AND_EXIT
75
76 def do_show(self, line):
77 """Show detailed device information"""
78 print_pb_as_table('Device {}'.format(self.device_id),
79 self.get_device(depth=-1))
80
81 def do_ports(self, line):
82 """Show ports of device"""
83 device = self.get_device(depth=-1)
84 omit_fields = {
85 }
86 print_pb_list_as_table('Device ports:', device.ports,
87 omit_fields, self.poutput)
88
89 def complete_perf_config(self, text, line, begidx, endidx):
90 sub_cmds = {"show", "set", "commit", "reset"}
91 sub_opts = {"-f", "-e", "-d", "-o"}
92 # Help the interpreter complete the paramters.
93 completions = []
94 if not self.pm_config_last:
95 device = self.get_device(depth=-1)
96 self.pm_config_last = device.pm_configs
97 m_names = [d.name for d in self.pm_config_last.metrics]
98 cur_cmd = line.strip().split(" ")
99 try:
100 if not text and len(cur_cmd) == 1:
101 completions = ("show", "set", "commit", "reset")
102 elif len(cur_cmd) == 2:
103 if "set" == cur_cmd[1]:
104 completions = [d for d in sub_opts]
105 else:
106 completions = [d for d in sub_cmds if d.startswith(text)]
107 elif len(cur_cmd) > 2 and cur_cmd[1] == "set":
108 if cur_cmd[len(cur_cmd)-1] == "-":
109 completions = [list(d)[1] for d in sub_opts]
110 elif cur_cmd[len(cur_cmd)-1] == "-f":
111 completions = ("\255","Please enter a sampling frequency in 10ths of a second")
112 elif cur_cmd[len(cur_cmd)-2] == "-f":
113 completions = [d for d in sub_opts]
114 elif cur_cmd[len(cur_cmd)-1] in {"-e","-d","-o"}:
115 if self.pm_config_last.grouped:
116 pass
117 else:
118 completions = [d.name for d in self.pm_config_last.metrics]
119 elif cur_cmd[len(cur_cmd)-2] in {"-e","-d"}:
120 if text and text not in m_names:
121 completions = [d for d in m_names if d.startswith(text)]
122 else:
123 completions = [d for d in sub_opts]
124 elif cur_cmd[len(cur_cmd)-2] == "-o":
125 if cur_cmd[len(cur_cmd)-1] in [d.name for d in self.pm_config_last.metrics]:
126 completions = ("\255","Please enter a sampling frequency in 10ths of a second")
127 else:
128 completions = [d for d in m_names if d.startswith(text)]
129 elif cur_cmd[len(cur_cmd)-3] == "-o":
130 completions = [d for d in sub_opts]
131 except:
132 e = sys.exc_info()
133 print(e)
134 return completions
135
136
137 def help_perf_config(self):
138 self.poutput(
139'''
140perf_config [show | set | commit | reset] [-f <default frequency>] [{-e <metric/group
141 name>}] [{-d <metric/group name>}] [{-o <metric/group name> <override
142 frequency>}]
143
144show: displays the performance configuration of the device
145set: changes the parameters specified with -e, -d, and -o
146reset: reverts any changes made since the last commit
147commit: commits any changes made which applies them to the device.
148
149-e: enable collection of the specified metric, more than one -e may be
150 specified.
151-d: disable collection of the specified metric, more than on -d may be
152 specified.
153-o: override the collection frequency of the specified metric, more than one -o
154 may be specified. Note that -o isn't valid unless
155 frequency_override is set to True for the device.
156
157Changes made by set are held locally until a commit or reset command is issued.
158A commit command will write the configuration to the device and it takes effect
159immediately. The reset command will undo any changes since the start of the
160device session.
161
162If grouped is true then the -d, -e and -o commands refer to groups and not
163individual metrics.
164'''
165 )
166
167 @options([
168 make_option('-f', '--default_freq', action="store", dest='default_freq',
169 type='long', default=None),
170 make_option('-e', '--enable', action='append', dest='enable',
171 default=None),
172 make_option('-d', '--disable', action='append', dest='disable',
173 default=None),
174 make_option('-o', '--override', action='append', dest='override',
175 nargs=2, default=None, type='string'),
176 ])
177 def do_perf_config(self, line, opts):
178 """Show and set the performance monitoring configuration of the device"""
179
180 device = self.get_device(depth=-1)
181 if not self.pm_config_last:
182 self.pm_config_last = device.pm_configs
183
184 # Ensure that a valid sub-command was provided
185 if line.strip() not in {"set", "show", "commit", "reset", ""}:
186 self.poutput(self.colorize('Error: ', 'red') +
187 self.colorize(self.colorize(line.strip(), 'blue'),
188 'bold') + ' is not recognized')
189 return
190
191 # Ensure no options are provided when requesting to view the config
192 if line.strip() == "show" or line.strip() == "":
193 if opts.default_freq or opts.enable or opts.disable:
194 self.poutput(opts.disable)
195 self.poutput(self.colorize('Error: ', 'red') + 'use ' +
196 self.colorize(self.colorize('"set"', 'blue'),
197 'bold') + ' to change settings')
198 return
199
200 if line.strip() == "set": # Set the supplied values
201 metric_list = set()
202 if opts.enable is not None:
203 metric_list |= {metric for metric in opts.enable}
204 if opts.disable is not None:
205 metric_list |= {metric for metric in opts.disable}
206 if opts.override is not None:
207 metric_list |= {metric for metric, _ in opts.override}
208
209 # The default frequency
210 if opts.default_freq:
211 self.pm_config_last.default_freq = opts.default_freq
212 self.pm_config_dirty = True
213
214 # Field or group visibility
215 if self.pm_config_last.grouped:
216 for g in self.pm_config_last.groups:
217 if opts.enable:
218 if g.group_name in opts.enable:
219 g.enabled = True
220 self.pm_config_dirty = True
221 metric_list.discard(g.group_name)
222 for g in self.pm_config_last.groups:
223 if opts.disable:
224 if g.group_name in opts.disable:
225 g.enabled = False
226 self.pm_config_dirty = True
227 metric_list.discard(g.group_name)
228 else:
229 for m in self.pm_config_last.metrics:
230 if opts.enable:
231 if m.name in opts.enable:
232 m.enabled = True
233 self.pm_config_dirty = True
234 metric_list.discard(m.name)
235 for m in self.pm_config_last.metrics:
236 if opts.disable:
237 if m.name in opts.disable:
238 m.enabled = False
239 self.pm_config_dirty = True
240 metric_list.discard(m.name)
241
242 # Frequency overrides.
243 if opts.override:
244 if self.pm_config_last.freq_override:
245 oo = dict()
246 for o in opts.override:
247 oo[o[0]] = o[1]
248 if self.pm_config_last.grouped:
249 for g in self.pm_config_last.groups:
250 if g.group_name in oo:
251 try:
252 g.group_freq = int(oo[g.group_name])
253 except ValueError:
254 self.poutput(self.colorize('Warning: ',
255 'yellow') +
256 self.colorize(oo[g.group_name],
257 'blue') +
258 " is not an integer... ignored")
259 del oo[g.group_name]
260 self.pm_config_dirty = True
261 metric_list.discard(g.group_name)
262 else:
263 for m in self.pm_config_last.metrics:
264 if m.name in oo:
265 try:
266 m.sample_freq = int(oo[m.name])
267 except ValueError:
268 self.poutput(self.colorize('Warning: ',
269 'yellow') +
270 self.colorize(oo[m.name],
271 'blue') +
272 " is not an integer... ignored")
273 del oo[m.name]
274 self.pm_config_dirty = True
275 metric_list.discard(m.name)
276
277 # If there's anything left the input was typoed
278 if self.pm_config_last.grouped:
279 field = 'group'
280 else:
281 field = 'metric'
282 for o in oo:
283 self.poutput(self.colorize('Warning: ', 'yellow') +
284 'the parameter' + ' ' +
285 self.colorize(o, 'blue') + ' is not ' +
286 'a ' + field + ' name... ignored')
287 if oo:
288 return
289
290 else: # Frequency overrides not enabled
291 self.poutput(self.colorize('Error: ', 'red') +
292 'Individual overrides are only ' +
293 'supported if ' +
294 self.colorize('freq_override', 'blue') +
295 ' is set to ' + self.colorize('True', 'blue'))
296 return
297
298 if len(metric_list):
299 metric_name_list = ", ".join(str(metric) for metric in metric_list)
300 self.poutput(self.colorize('Error: ', 'red') +
301 'Metric/Metric Group{} '.format('s' if len(metric_list) > 1 else '') +
302 self.colorize(metric_name_list, 'blue') +
303 ' {} not found'.format('were' if len(metric_list) > 1 else 'was'))
304 return
305
306 self.poutput("Success")
307 return
308
309 elif line.strip() == "commit" and self.pm_config_dirty:
310 stub = self.get_stub()
311 stub.UpdateDevicePmConfigs(self.pm_config_last)
312 self.pm_config_last = self.get_device(depth=-1).pm_configs
313 self.pm_config_dirty = False
314
315 elif line.strip() == "reset" and self.pm_config_dirty:
316 self.pm_config_last = self.get_device(depth=-1).pm_configs
317 self.pm_config_dirty = False
318
319 omit_fields = {'groups', 'metrics', 'id'}
320 print_pb_as_table('PM Config:', self.pm_config_last, omit_fields,
321 self.poutput,show_nulls=True)
322 if self.pm_config_last.grouped:
323 #self.poutput("Supported metric groups:")
324 for g in self.pm_config_last.groups:
325 if self.pm_config_last.freq_override:
326 omit_fields = {'metrics'}
327 else:
328 omit_fields = {'group_freq','metrics'}
329 print_pb_as_table('', g, omit_fields, self.poutput,
330 show_nulls=True)
331 if g.enabled:
332 state = 'enabled'
333 else:
334 state = 'disabled'
335 print_pb_list_as_table(
336 'Metric group {} is {}'.format(g.group_name,state),
337 g.metrics, {'enabled', 'sample_freq'}, self.poutput,
338 dividers=100, show_nulls=True)
339 else:
340 if self.pm_config_last.freq_override:
341 omit_fields = {}
342 else:
343 omit_fields = {'sample_freq'}
344 print_pb_list_as_table('Supported metrics:', self.pm_config_last.metrics,
345 omit_fields, self.poutput, dividers=100,
346 show_nulls=True)
347
348 def do_flows(self, line):
349 """Show flow table for device"""
350 device = pb2dict(self.get_device(-1))
351 print_flows(
352 'Device',
353 self.device_id,
354 type=device['type'],
355 flows=device['flows']['items'],
356 groups=device['flow_groups']['items']
357 )
358
359 def do_images(self, line):
360 """Show software images on the device"""
361 device = self.get_device(depth=-1)
362 omit_fields = {}
363 print_pb_list_as_table('Software Images:', device.images.image,
364 omit_fields, self.poutput, show_nulls=True)
365
366 @options([
367 make_option('-u', '--url', action='store', dest='url',
368 help="URL to get sw image"),
369 make_option('-n', '--name', action='store', dest='name',
370 help="Image name"),
371 make_option('-c', '--crc', action='store', dest='crc',
372 help="CRC code to verify with", default=0),
373 make_option('-v', '--version', action='store', dest='version',
374 help="Image version", default=0),
375 ])
376 def do_img_dnld_request(self, line, opts):
377 """
378 Request image download to a device
379 """
380 device = self.get_device(depth=-1)
381 self.poutput('device_id {}'.format(device.id))
382 self.poutput('name {}'.format(opts.name))
383 self.poutput('url {}'.format(opts.url))
384 self.poutput('crc {}'.format(opts.crc))
385 self.poutput('version {}'.format(opts.version))
386 try:
387 device_id = device.id
388 if device_id and opts.name and opts.url:
389 kw = dict(id=device_id)
390 kw['name'] = opts.name
391 kw['url'] = opts.url
392 else:
393 self.poutput('Device ID and URL are needed')
394 raise Exception('Device ID and URL are needed')
395 except Exception as e:
396 self.poutput('Error request img dnld {}. Error:{}'.format(device_id, e))
397 return
398 kw['crc'] = long(opts.crc)
399 kw['image_version'] = opts.version
400 response = None
401 try:
402 request = voltha_pb2.ImageDownload(**kw)
403 stub = self.get_stub()
404 response = stub.DownloadImage(request)
405 except Exception as e:
406 self.poutput('Error download image {}. Error:{}'.format(kw['id'], e))
407 return
408 name = enum2name(common_pb2.OperationResp,
409 'OperationReturnCode', response.code)
410 self.poutput('response: {}'.format(name))
411 self.poutput('{}'.format(response))
412
413 @options([
414 make_option('-n', '--name', action='store', dest='name',
415 help="Image name"),
416 ])
417 def do_img_dnld_status(self, line, opts):
418 """
419 Get a image download status
420 """
421 device = self.get_device(depth=-1)
422 self.poutput('device_id {}'.format(device.id))
423 self.poutput('name {}'.format(opts.name))
424 try:
425 device_id = device.id
426 if device_id and opts.name:
427 kw = dict(id=device_id)
428 kw['name'] = opts.name
429 else:
430 self.poutput('Device ID, Image Name are needed')
431 raise Exception('Device ID, Image Name are needed')
432 except Exception as e:
433 self.poutput('Error get img dnld status {}. Error:{}'.format(device_id, e))
434 return
435 status = None
436 try:
437 img_dnld = voltha_pb2.ImageDownload(**kw)
438 stub = self.get_stub()
439 status = stub.GetImageDownloadStatus(img_dnld)
440 except Exception as e:
441 self.poutput('Error get img dnld status {}. Error:{}'.format(device_id, e))
442 return
443 fields_to_omit = {
444 'crc',
445 'local_dir',
446 }
447 try:
448 print_pb_as_table('ImageDownload Status:', status, fields_to_omit, self.poutput)
449 except Exception, e:
450 self.poutput('Error {}. Error:{}'.format(device_id, e))
451
452 def do_img_dnld_list(self, line):
453 """
454 List all image download records for a given device
455 """
456 device = self.get_device(depth=-1)
457 device_id = device.id
458 self.poutput('Get all img dnld records {}'.format(device_id))
459 try:
460 stub = self.get_stub()
461 img_dnlds = stub.ListImageDownloads(voltha_pb2.ID(id=device_id))
462 except Exception, e:
463 self.poutput('Error list img dnlds {}. Error:{}'.format(device_id, e))
464 return
465 fields_to_omit = {
466 'crc',
467 'local_dir',
468 }
469 try:
470 print_pb_list_as_table('ImageDownloads:', img_dnlds.items, fields_to_omit, self.poutput)
471 except Exception, e:
472 self.poutput('Error {}. Error:{}'.format(device_id, e))
473
474
475 @options([
476 make_option('-n', '--name', action='store', dest='name',
477 help="Image name"),
478 ])
479 def do_img_dnld_cancel(self, line, opts):
480 """
481 Cancel a requested image download
482 """
483 device = self.get_device(depth=-1)
484 self.poutput('device_id {}'.format(device.id))
485 self.poutput('name {}'.format(opts.name))
486 device_id = device.id
487 try:
488 if device_id and opts.name:
489 kw = dict(id=device_id)
490 kw['name'] = opts.name
491 else:
492 self.poutput('Device ID, Image Name are needed')
493 raise Exception('Device ID, Image Name are needed')
494 except Exception as e:
495 self.poutput('Error cancel sw dnld {}. Error:{}'.format(device_id, e))
496 return
497 response = None
498 try:
499 img_dnld = voltha_pb2.ImageDownload(**kw)
500 stub = self.get_stub()
501 img_dnld = stub.GetImageDownload(img_dnld)
502 response = stub.CancelImageDownload(img_dnld)
503 except Exception as e:
504 self.poutput('Error cancel sw dnld {}. Error:{}'.format(device_id, e))
505 return
506 name = enum2name(common_pb2.OperationResp,
507 'OperationReturnCode', response.code)
508 self.poutput('response: {}'.format(name))
509 self.poutput('{}'.format(response))
510
serkant.uluderya334479d2019-04-10 08:26:15 -0700511 def help_simulate_alarm(self):
512 self.poutput(
513'''
514simulate_alarm <alarm_name> [-b <bit rate>] [-c] [-d <drift>] [-e <eqd>]
515 [-i <interface id>] [-o <onu device id>] [-p <port type name>]
516
517<name> is the name of the alarm to raise. Other rguments are alarm specific
518and only have meaning in the context of a particular alarm. Below is a list
519of the alarms that may be raised:
520
521simulate_alarm los -i <interface_id> -p <port_type_name>
522simulate_alarm dying_gasp -i <interface_id> -o <onu_device_id>
523simulate_alarm onu_los -i <interface_id> -o <onu_device_id>
524simulate_alarm onu_lopc_miss -i <interface_id> -o <onu_device_id>
525simulate_alarm onu_lopc_mic -i <interface_id> -o <onu_device_id>
526simulate_alarm onu_lob -i <interface_id> -o <onu_device_id>
527simulate_alarm onu_signal_degrade -i <interface_id> -o <onu_device_id>
528 -b <bit_rate>
529simulate_alarm onu_drift_of_window -i <interface_id>
530 -o <onu_device_id> -d <drift> -e <eqd>
531simulate_alarm onu_signal_fail -i <interface_id> -o <onu_device_id>
532 -b <bit_rate>
533simulate_alarm onu_activation -i <interface_id> -o <onu_device_id>
534simulate_alarm onu_startup -i <interface_id> -o <onu_device_id>
535simulate_alarm onu_discovery -i <interface_id> -s <onu_serial_number>
536
537If the -c option is specified then the alarm will be cleared. By default,
538it will be raised. Note that only some alarms can be cleared.
539'''
540 )
541
542 @options([
543 make_option('-c', '--clear', action='store_true', default=False,
544 help="Clear alarm instead of raising"),
545 make_option('-b', '--inverse_bit_error_rate', action='store', dest='inverse_bit_error_rate',
546 help="Inverse bit error rate", default=0, type="int"),
547 make_option('-d', '--drift', action='store', dest='drift',
548 help="Drift", default=0, type="int"),
549 make_option('-e', '--new_eqd', action='store', dest='new_eqd',
550 help="New EQD", default=0, type="int"),
551 make_option('-i', '--intf_id', action='store', dest='intf_id',
552 help="Interface ID", default=""),
553 make_option('-o', '--onu_device_id', action='store', dest='onu_device_id',
554 help="ONU device ID", default=""),
555 make_option('-p', '--port_type_name', action='store', dest='port_type_name',
556 help="Port type name", default=""),
557 make_option('-s', '--onu_serial_number', action='store', dest='onu_serial_number',
558 help="ONU Serial Number", default=""),
559 ])
560 def do_simulate_alarm(self, line, opts):
561 indicator = line
562 device = self.get_device(depth=-1)
563 device_id = device.id
564
565 alarm_args = {"los": ["intf_id", "port_type_name"],
566 "dying_gasp": ["intf_id", "onu_device_id"],
567 "onu_los": ["intf_id", "onu_device_id"],
568 "onu_lopc_miss": ["intf_id", "onu_device_id"],
569 "onu_lopc_mic": ["intf_id", "onu_device_id"],
570 "onu_lob": ["intf_id", "onu_device_id"],
571 "onu_signal_degrade": ["intf_id", "onu_device_id", "inverse_bit_error_rate"],
572 "onu_drift_of_window": ["intf_id", "onu_device_id", "drift", "new_eqd"],
573 "onu_signal_fail": ["intf_id", "onu_device_id", "inverse_bit_error_rate"],
574 "onu_activation": ["intf_id", "onu_device_id"],
575 "onu_startup": ["intf_id", "onu_device_id"],
576 "onu_discovery": ["intf_id", "onu_serial_number"]
577 }
578 try:
579 if indicator not in alarm_args:
580 self.poutput("Unknown alarm indicator %s. Valid choices are %s." % (indicator,
581 ", ".join(alarm_args.keys())))
582 raise Exception("Unknown alarm indicator %s" % indicator)
583
584 for arg_name in alarm_args[indicator]:
585 if not getattr(opts, arg_name):
586 self.poutput("Option %s is required for alarm %s. See help." % (arg_name, indicator))
587 raise Exception("Option %s is required for alarm %s" % (arg_name, indicator))
588
589 # TODO: check for required arguments
590 kw = dict(id=device_id)
591
592 kw["indicator"] = indicator
593 kw["intf_id"] = opts.intf_id
594 kw["onu_device_id"] = opts.onu_device_id
595 kw["port_type_name"] = opts.port_type_name
596 kw["inverse_bit_error_rate"] = opts.inverse_bit_error_rate
597 kw["drift"] = opts.drift
598 kw["new_eqd"] = opts.new_eqd
599 kw["onu_serial_number"] = opts.onu_serial_number
600
601 if opts.clear:
602 kw["operation"] = voltha_pb2.SimulateAlarmRequest.CLEAR
603 else:
604 kw["operation"] = voltha_pb2.SimulateAlarmRequest.RAISE
605 except Exception as e:
606 self.poutput('Error simulate alarm {}. Error:{}'.format(device_id, e))
607 return
608 response = None
609 try:
610 simulate_alarm = voltha_pb2.SimulateAlarmRequest(**kw)
611 stub = self.get_stub()
612 response = stub.SimulateAlarm(simulate_alarm)
613 except Exception as e:
614 self.poutput('Error simulate alarm {}. Error:{}'.format(kw['id'], e))
615 return
616 name = enum2name(common_pb2.OperationResp,
617 'OperationReturnCode', response.code)
618 self.poutput('response: {}'.format(name))
619 self.poutput('{}'.format(response))
620
khenaidoofdbad6e2018-11-06 22:26:38 -0500621 @options([
622 make_option('-n', '--name', action='store', dest='name',
623 help="Image name"),
624 make_option('-s', '--save', action='store', dest='save_config',
625 help="Save Config", default="True"),
626 make_option('-d', '--dir', action='store', dest='local_dir',
627 help="Image on device location"),
628 ])
629 def do_img_activate(self, line, opts):
630 """
631 Activate an image update on device
632 """
633 device = self.get_device(depth=-1)
634 device_id = device.id
635 try:
636 if device_id and opts.name and opts.local_dir:
637 kw = dict(id=device_id)
638 kw['name'] = opts.name
639 kw['local_dir'] = opts.local_dir
640 else:
641 self.poutput('Device ID, Image Name, and Location are needed')
642 raise Exception('Device ID, Image Name, and Location are needed')
643 except Exception as e:
644 self.poutput('Error activate image {}. Error:{}'.format(device_id, e))
645 return
646 kw['save_config'] = json.loads(opts.save_config.lower())
647 self.poutput('activate image update {} {} {} {}'.format( \
648 kw['id'], kw['name'],
649 kw['local_dir'], kw['save_config']))
650 response = None
651 try:
652 img_dnld = voltha_pb2.ImageDownload(**kw)
653 stub = self.get_stub()
654 img_dnld = stub.GetImageDownload(img_dnld)
655 response = stub.ActivateImageUpdate(img_dnld)
656 except Exception as e:
657 self.poutput('Error activate image {}. Error:{}'.format(kw['id'], e))
658 return
659 name = enum2name(common_pb2.OperationResp,
660 'OperationReturnCode', response.code)
661 self.poutput('response: {}'.format(name))
662 self.poutput('{}'.format(response))
663
664 @options([
665 make_option('-n', '--name', action='store', dest='name',
666 help="Image name"),
667 make_option('-s', '--save', action='store', dest='save_config',
668 help="Save Config", default="True"),
669 make_option('-d', '--dir', action='store', dest='local_dir',
670 help="Image on device location"),
671 ])
672 def do_img_revert(self, line, opts):
673 """
674 Revert an image update on device
675 """
676 device = self.get_device(depth=-1)
677 device_id = device.id
678 try:
679 if device_id and opts.name and opts.local_dir:
680 kw = dict(id=device_id)
681 kw['name'] = opts.name
682 kw['local_dir'] = opts.local_dir
683 else:
684 self.poutput('Device ID, Image Name, and Location are needed')
685 raise Exception('Device ID, Image Name, and Location are needed')
686 except Exception as e:
687 self.poutput('Error revert image {}. Error:{}'.format(device_id, e))
688 return
689 kw['save_config'] = json.loads(opts.save_config.lower())
690 self.poutput('revert image update {} {} {} {}'.format( \
691 kw['id'], kw['name'],
692 kw['local_dir'], kw['save_config']))
693 response = None
694 try:
695 img_dnld = voltha_pb2.ImageDownload(**kw)
696 stub = self.get_stub()
697 img_dnld = stub.GetImageDownload(img_dnld)
698 response = stub.RevertImageUpdate(img_dnld)
699 except Exception as e:
700 self.poutput('Error revert image {}. Error:{}'.format(kw['id'], e))
701 return
702 name = enum2name(common_pb2.OperationResp,
703 'OperationReturnCode', response.code)
704 self.poutput('response: {}'.format(name))
705 self.poutput('{}'.format(response))