blob: 6579690929753ea8b838835fd0e186640ddc38d5 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2 * Copyright 2019-present Ciena Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package commands
17
18import (
19 "context"
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -080020 "errors"
Zack Williamse940c7a2019-08-21 14:25:39 -070021 "fmt"
David Bainbridge7052fe82020-03-25 10:37:00 -070022 "os"
23 "strconv"
24 "strings"
25
Zack Williamse940c7a2019-08-21 14:25:39 -070026 "github.com/fullstorydev/grpcurl"
27 flags "github.com/jessevdk/go-flags"
28 "github.com/jhump/protoreflect/dynamic"
Scott Baker2b0ad652019-08-21 14:57:07 -070029 "github.com/opencord/voltctl/pkg/format"
30 "github.com/opencord/voltctl/pkg/model"
Zack Williamse940c7a2019-08-21 14:25:39 -070031)
32
33const (
David K. Bainbridge89003c42020-02-27 17:22:49 -080034 DEFAULT_DEVICE_FORMAT = "table{{ .Id }}\t{{.Type}}\t{{.Root}}\t{{.ParentId}}\t{{.SerialNumber}}\t{{.AdminState}}\t{{.OperStatus}}\t{{.ConnectStatus}}\t{{.Reason}}"
Zack Williamse940c7a2019-08-21 14:25:39 -070035 DEFAULT_DEVICE_PORTS_FORMAT = "table{{.PortNo}}\t{{.Label}}\t{{.Type}}\t{{.AdminState}}\t{{.OperStatus}}\t{{.DeviceId}}\t{{.Peers}}"
36 DEFAULT_DEVICE_INSPECT_FORMAT = `ID: {{.Id}}
37 TYPE: {{.Type}}
38 ROOT: {{.Root}}
39 PARENTID: {{.ParentId}}
40 SERIALNUMBER: {{.SerialNumber}}
41 VLAN: {{.Vlan}}
42 ADMINSTATE: {{.AdminState}}
43 OPERSTATUS: {{.OperStatus}}
44 CONNECTSTATUS: {{.ConnectStatus}}`
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -080045 DEFAULT_DEVICE_VALUE_GET_FORMAT = "table{{.Name}}\t{{.Result}}"
Zack Williamse940c7a2019-08-21 14:25:39 -070046)
47
48type DeviceList struct {
49 ListOutputOptions
50}
51
52type DeviceCreate struct {
David Bainbridge835dd0e2020-04-01 10:30:09 -070053 DeviceType string `short:"t" long:"devicetype" default:"" description:"Device type"`
54 MACAddress string `short:"m" long:"macaddress" default:"" description:"MAC Address"`
Zack Williamse940c7a2019-08-21 14:25:39 -070055 IPAddress string `short:"i" long:"ipaddress" default:"" description:"IP Address"`
56 HostAndPort string `short:"H" long:"hostandport" default:"" description:"Host and port"`
57}
58
59type DeviceId string
60
kesavand12cd8eb2020-01-20 22:25:22 -050061type PortNum uint32
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -080062type ValueFlag string
kesavand12cd8eb2020-01-20 22:25:22 -050063
Zack Williamse940c7a2019-08-21 14:25:39 -070064type DeviceDelete struct {
65 Args struct {
66 Ids []DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
67 } `positional-args:"yes"`
68}
69
70type DeviceEnable struct {
71 Args struct {
72 Ids []DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
73 } `positional-args:"yes"`
74}
75
76type DeviceDisable struct {
77 Args struct {
78 Ids []DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
79 } `positional-args:"yes"`
80}
81
82type DeviceReboot struct {
83 Args struct {
84 Ids []DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
85 } `positional-args:"yes"`
86}
87
88type DeviceFlowList struct {
89 ListOutputOptions
90 Args struct {
91 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
92 } `positional-args:"yes"`
93}
94
95type DevicePortList struct {
96 ListOutputOptions
97 Args struct {
98 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
99 } `positional-args:"yes"`
100}
101
102type DeviceInspect struct {
103 OutputOptionsJson
104 Args struct {
105 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
106 } `positional-args:"yes"`
107}
108
kesavand12cd8eb2020-01-20 22:25:22 -0500109type DevicePortEnable struct {
110 Args struct {
111 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
112 PortId PortNum `positional-arg-name:"PORT_NUMBER" required:"yes"`
113 } `positional-args:"yes"`
114}
115
116type DevicePortDisable struct {
117 Args struct {
118 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
119 PortId PortNum `positional-arg-name:"PORT_NUMBER" required:"yes"`
120 } `positional-args:"yes"`
121}
122
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -0800123type DeviceGetExtValue struct {
124 ListOutputOptions
125 Args struct {
126 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
127 Valueflag ValueFlag `positional-arg-name:"VALUE_FLAG" required:"yes"`
128 } `positional-args:"yes"`
129}
Zack Williamse940c7a2019-08-21 14:25:39 -0700130type DeviceOpts struct {
131 List DeviceList `command:"list"`
132 Create DeviceCreate `command:"create"`
133 Delete DeviceDelete `command:"delete"`
134 Enable DeviceEnable `command:"enable"`
135 Disable DeviceDisable `command:"disable"`
136 Flows DeviceFlowList `command:"flows"`
kesavand12cd8eb2020-01-20 22:25:22 -0500137 Port struct {
138 List DevicePortList `command:"list"`
139 Enable DevicePortEnable `command:"enable"`
140 Disable DevicePortDisable `command:"disable"`
141 } `command:"port"`
142 Inspect DeviceInspect `command:"inspect"`
143 Reboot DeviceReboot `command:"reboot"`
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -0800144 Value struct {
145 Get DeviceGetExtValue `command:"get"`
146 } `command:"value"`
Zack Williamse940c7a2019-08-21 14:25:39 -0700147}
148
149var deviceOpts = DeviceOpts{}
150
151func RegisterDeviceCommands(parser *flags.Parser) {
David Bainbridge12f036f2019-10-15 22:09:04 +0000152 if _, err := parser.AddCommand("device", "device commands", "Commands to query and manipulate VOLTHA devices", &deviceOpts); err != nil {
David Bainbridgea6722342019-10-24 23:55:53 +0000153 Error.Fatalf("Unexpected error while attempting to register device commands : %s", err)
David Bainbridge12f036f2019-10-15 22:09:04 +0000154 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700155}
156
kesavand12cd8eb2020-01-20 22:25:22 -0500157func (i *PortNum) Complete(match string) []flags.Completion {
158 conn, err := NewConnection()
159 if err != nil {
160 return nil
161 }
162 defer conn.Close()
163
164 descriptor, method, err := GetMethod("device-ports")
165 if err != nil {
166 return nil
167 }
168
169 /*
170 * The command line args when completing for PortNum will be a DeviceId
171 * followed by one or more PortNums. So walk the argument list from the
172 * end and find the first argument that is enable/disable as those are
173 * the subcommands that come before the positional arguments. It would
174 * be nice if this package gave us the list of optional arguments
175 * already parsed.
176 */
177 var deviceId string
178found:
179 for i := len(os.Args) - 1; i >= 0; i -= 1 {
180 switch os.Args[i] {
181 case "enable":
182 fallthrough
183 case "disable":
184 if len(os.Args) > i+1 {
185 deviceId = os.Args[i+1]
186 } else {
187 return nil
188 }
189 break found
190 default:
191 }
192 }
193
194 if len(deviceId) == 0 {
195 return nil
196 }
197
198 h := &RpcEventHandler{
199 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": deviceId}},
200 }
201 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
202 defer cancel()
203 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
204 if err != nil {
205 return nil
206 }
207
208 if h.Status != nil && h.Status.Err() != nil {
209 return nil
210 }
211
212 d, err := dynamic.AsDynamicMessage(h.Response)
213 if err != nil {
214 return nil
215 }
216
217 items, err := d.TryGetFieldByName("items")
218 if err != nil {
219 return nil
220 }
221
222 list := make([]flags.Completion, 0)
223 for _, item := range items.([]interface{}) {
224 val := item.(*dynamic.Message)
225 pn := strconv.FormatUint(uint64(val.GetFieldByName("port_no").(uint32)), 10)
226 if strings.HasPrefix(pn, match) {
227 list = append(list, flags.Completion{Item: pn})
228 }
229 }
230
231 return list
232}
233
Zack Williamse940c7a2019-08-21 14:25:39 -0700234func (i *DeviceId) Complete(match string) []flags.Completion {
235 conn, err := NewConnection()
236 if err != nil {
237 return nil
238 }
239 defer conn.Close()
240
241 descriptor, method, err := GetMethod("device-list")
242 if err != nil {
243 return nil
244 }
245
246 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
247 defer cancel()
248
249 h := &RpcEventHandler{}
250 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
251 if err != nil {
252 return nil
253 }
254
255 if h.Status != nil && h.Status.Err() != nil {
256 return nil
257 }
258
259 d, err := dynamic.AsDynamicMessage(h.Response)
260 if err != nil {
261 return nil
262 }
263
264 items, err := d.TryGetFieldByName("items")
265 if err != nil {
266 return nil
267 }
268
269 list := make([]flags.Completion, 0)
270 for _, item := range items.([]interface{}) {
271 val := item.(*dynamic.Message)
272 id := val.GetFieldByName("id").(string)
273 if strings.HasPrefix(id, match) {
274 list = append(list, flags.Completion{Item: id})
275 }
276 }
277
278 return list
279}
280
281func (options *DeviceList) Execute(args []string) error {
282
283 conn, err := NewConnection()
284 if err != nil {
285 return err
286 }
287 defer conn.Close()
288
289 descriptor, method, err := GetMethod("device-list")
290 if err != nil {
291 return err
292 }
293
294 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
295 defer cancel()
296
297 h := &RpcEventHandler{}
298 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
299 if err != nil {
300 return err
301 }
302
303 if h.Status != nil && h.Status.Err() != nil {
304 return h.Status.Err()
305 }
306
307 d, err := dynamic.AsDynamicMessage(h.Response)
308 if err != nil {
309 return err
310 }
311
312 items, err := d.TryGetFieldByName("items")
313 if err != nil {
314 return err
315 }
316
317 outputFormat := CharReplacer.Replace(options.Format)
318 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000319 outputFormat = GetCommandOptionWithDefault("device-list", "format", DEFAULT_DEVICE_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700320 }
321 if options.Quiet {
322 outputFormat = "{{.Id}}"
323 }
324
David Bainbridgea6722342019-10-24 23:55:53 +0000325 orderBy := options.OrderBy
326 if orderBy == "" {
327 orderBy = GetCommandOptionWithDefault("device-list", "order", "")
328 }
329
Zack Williamse940c7a2019-08-21 14:25:39 -0700330 data := make([]model.Device, len(items.([]interface{})))
331 for i, item := range items.([]interface{}) {
332 val := item.(*dynamic.Message)
333 data[i].PopulateFrom(val)
334 }
335
336 result := CommandResult{
337 Format: format.Format(outputFormat),
338 Filter: options.Filter,
David Bainbridgea6722342019-10-24 23:55:53 +0000339 OrderBy: orderBy,
Zack Williamse940c7a2019-08-21 14:25:39 -0700340 OutputAs: toOutputType(options.OutputAs),
341 NameLimit: options.NameLimit,
342 Data: data,
343 }
344
345 GenerateOutput(&result)
346 return nil
347}
348
349func (options *DeviceCreate) Execute(args []string) error {
350
351 dm := make(map[string]interface{})
352 if options.HostAndPort != "" {
353 dm["host_and_port"] = options.HostAndPort
354 } else if options.IPAddress != "" {
355 dm["ipv4_address"] = options.IPAddress
Hardik Windlassce1de342020-02-04 21:58:07 +0000356 }
357 if options.MACAddress != "" {
Zack Williamse940c7a2019-08-21 14:25:39 -0700358 dm["mac_address"] = strings.ToLower(options.MACAddress)
359 }
360 if options.DeviceType != "" {
361 dm["type"] = options.DeviceType
362 }
363
364 conn, err := NewConnection()
365 if err != nil {
366 return err
367 }
368 defer conn.Close()
369
370 descriptor, method, err := GetMethod("device-create")
371 if err != nil {
372 return err
373 }
374
375 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
376 defer cancel()
377
378 h := &RpcEventHandler{
379 Fields: map[string]map[string]interface{}{"voltha.Device": dm},
380 }
381 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
382 if err != nil {
383 return err
384 } else if h.Status != nil && h.Status.Err() != nil {
385 return h.Status.Err()
386 }
387
388 resp, err := dynamic.AsDynamicMessage(h.Response)
389 if err != nil {
390 return err
391 }
392 fmt.Printf("%s\n", resp.GetFieldByName("id").(string))
393
394 return nil
395}
396
397func (options *DeviceDelete) Execute(args []string) error {
398
399 conn, err := NewConnection()
400 if err != nil {
401 return err
402 }
403 defer conn.Close()
404
405 descriptor, method, err := GetMethod("device-delete")
406 if err != nil {
407 return err
408 }
409
David Bainbridge7052fe82020-03-25 10:37:00 -0700410 var lastErr error
Zack Williamse940c7a2019-08-21 14:25:39 -0700411 for _, i := range options.Args.Ids {
412
413 h := &RpcEventHandler{
414 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": i}},
415 }
416 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
417 defer cancel()
418
419 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
420 if err != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000421 Error.Printf("Error while deleting '%s': %s\n", i, err)
David Bainbridge7052fe82020-03-25 10:37:00 -0700422 lastErr = err
Zack Williamse940c7a2019-08-21 14:25:39 -0700423 continue
424 } else if h.Status != nil && h.Status.Err() != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000425 Error.Printf("Error while deleting '%s': %s\n", i, ErrorToString(h.Status.Err()))
David Bainbridge7052fe82020-03-25 10:37:00 -0700426 lastErr = h.Status.Err()
Zack Williamse940c7a2019-08-21 14:25:39 -0700427 continue
428 }
429 fmt.Printf("%s\n", i)
430 }
431
David Bainbridge7052fe82020-03-25 10:37:00 -0700432 if lastErr != nil {
433 return NoReportErr
434 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700435 return nil
436}
437
438func (options *DeviceEnable) Execute(args []string) error {
439 conn, err := NewConnection()
440 if err != nil {
441 return err
442 }
443 defer conn.Close()
444
445 descriptor, method, err := GetMethod("device-enable")
446 if err != nil {
447 return err
448 }
449
David Bainbridge7052fe82020-03-25 10:37:00 -0700450 var lastErr error
Zack Williamse940c7a2019-08-21 14:25:39 -0700451 for _, i := range options.Args.Ids {
452 h := &RpcEventHandler{
453 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": i}},
454 }
455 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
456 defer cancel()
457
458 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
459 if err != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000460 Error.Printf("Error while enabling '%s': %s\n", i, err)
David Bainbridge7052fe82020-03-25 10:37:00 -0700461 lastErr = err
Zack Williamse940c7a2019-08-21 14:25:39 -0700462 continue
463 } else if h.Status != nil && h.Status.Err() != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000464 Error.Printf("Error while enabling '%s': %s\n", i, ErrorToString(h.Status.Err()))
David Bainbridge7052fe82020-03-25 10:37:00 -0700465 lastErr = h.Status.Err()
Zack Williamse940c7a2019-08-21 14:25:39 -0700466 continue
467 }
468 fmt.Printf("%s\n", i)
469 }
470
David Bainbridge7052fe82020-03-25 10:37:00 -0700471 if lastErr != nil {
472 return NoReportErr
473 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700474 return nil
475}
476
477func (options *DeviceDisable) Execute(args []string) error {
478 conn, err := NewConnection()
479 if err != nil {
480 return err
481 }
482 defer conn.Close()
483
484 descriptor, method, err := GetMethod("device-disable")
485 if err != nil {
486 return err
487 }
488
David Bainbridge7052fe82020-03-25 10:37:00 -0700489 var lastErr error
Zack Williamse940c7a2019-08-21 14:25:39 -0700490 for _, i := range options.Args.Ids {
491 h := &RpcEventHandler{
492 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": i}},
493 }
494 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
495 defer cancel()
496
497 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
498 if err != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000499 Error.Printf("Error while disabling '%s': %s\n", i, err)
David Bainbridge7052fe82020-03-25 10:37:00 -0700500 lastErr = err
Zack Williamse940c7a2019-08-21 14:25:39 -0700501 continue
502 } else if h.Status != nil && h.Status.Err() != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000503 Error.Printf("Error while disabling '%s': %s\n", i, ErrorToString(h.Status.Err()))
David Bainbridge7052fe82020-03-25 10:37:00 -0700504 lastErr = h.Status.Err()
Zack Williamse940c7a2019-08-21 14:25:39 -0700505 continue
506 }
507 fmt.Printf("%s\n", i)
508 }
509
David Bainbridge7052fe82020-03-25 10:37:00 -0700510 if lastErr != nil {
511 return NoReportErr
512 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700513 return nil
514}
515
516func (options *DeviceReboot) Execute(args []string) error {
517 conn, err := NewConnection()
518 if err != nil {
519 return err
520 }
521 defer conn.Close()
522
523 descriptor, method, err := GetMethod("device-reboot")
524 if err != nil {
525 return err
526 }
527
David Bainbridge7052fe82020-03-25 10:37:00 -0700528 var lastErr error
Zack Williamse940c7a2019-08-21 14:25:39 -0700529 for _, i := range options.Args.Ids {
530 h := &RpcEventHandler{
531 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": i}},
532 }
533 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
534 defer cancel()
535
536 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
537 if err != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000538 Error.Printf("Error while rebooting '%s': %s\n", i, err)
David Bainbridge7052fe82020-03-25 10:37:00 -0700539 lastErr = err
Zack Williamse940c7a2019-08-21 14:25:39 -0700540 continue
541 } else if h.Status != nil && h.Status.Err() != nil {
David Bainbridge0f758d42019-10-26 05:17:48 +0000542 Error.Printf("Error while rebooting '%s': %s\n", i, ErrorToString(h.Status.Err()))
David Bainbridge7052fe82020-03-25 10:37:00 -0700543 lastErr = h.Status.Err()
Zack Williamse940c7a2019-08-21 14:25:39 -0700544 continue
545 }
546 fmt.Printf("%s\n", i)
547 }
548
David Bainbridge7052fe82020-03-25 10:37:00 -0700549 if lastErr != nil {
550 return NoReportErr
551 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700552 return nil
553}
554
555func (options *DevicePortList) Execute(args []string) error {
556
557 conn, err := NewConnection()
558 if err != nil {
559 return err
560 }
561 defer conn.Close()
562
563 descriptor, method, err := GetMethod("device-ports")
564 if err != nil {
565 return err
566 }
567
568 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
569 defer cancel()
570
571 h := &RpcEventHandler{
572 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": options.Args.Id}},
573 }
574 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
575 if err != nil {
576 return err
577 }
578
579 if h.Status != nil && h.Status.Err() != nil {
580 return h.Status.Err()
581 }
582
583 d, err := dynamic.AsDynamicMessage(h.Response)
584 if err != nil {
585 return err
586 }
587
588 items, err := d.TryGetFieldByName("items")
589 if err != nil {
590 return err
591 }
592
593 outputFormat := CharReplacer.Replace(options.Format)
594 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000595 outputFormat = GetCommandOptionWithDefault("device-ports", "format", DEFAULT_DEVICE_PORTS_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700596 }
597 if options.Quiet {
598 outputFormat = "{{.Id}}"
599 }
600
David Bainbridgea6722342019-10-24 23:55:53 +0000601 orderBy := options.OrderBy
602 if orderBy == "" {
603 orderBy = GetCommandOptionWithDefault("device-ports", "order", "")
604 }
605
Zack Williamse940c7a2019-08-21 14:25:39 -0700606 data := make([]model.DevicePort, len(items.([]interface{})))
607 for i, item := range items.([]interface{}) {
608 data[i].PopulateFrom(item.(*dynamic.Message))
609 }
610
611 result := CommandResult{
612 Format: format.Format(outputFormat),
613 Filter: options.Filter,
David Bainbridgea6722342019-10-24 23:55:53 +0000614 OrderBy: orderBy,
Zack Williamse940c7a2019-08-21 14:25:39 -0700615 OutputAs: toOutputType(options.OutputAs),
616 NameLimit: options.NameLimit,
617 Data: data,
618 }
619
620 GenerateOutput(&result)
621 return nil
622}
623
624func (options *DeviceFlowList) Execute(args []string) error {
625 fl := &FlowList{}
626 fl.ListOutputOptions = options.ListOutputOptions
627 fl.Args.Id = string(options.Args.Id)
David Bainbridgea6722342019-10-24 23:55:53 +0000628 fl.Method = "device-flows"
Zack Williamse940c7a2019-08-21 14:25:39 -0700629 return fl.Execute(args)
630}
631
632func (options *DeviceInspect) Execute(args []string) error {
633 if len(args) > 0 {
634 return fmt.Errorf("only a single argument 'DEVICE_ID' can be provided")
635 }
636
637 conn, err := NewConnection()
638 if err != nil {
639 return err
640 }
641 defer conn.Close()
642
643 descriptor, method, err := GetMethod("device-inspect")
644 if err != nil {
645 return err
646 }
647
648 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
649 defer cancel()
650
651 h := &RpcEventHandler{
652 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ID"]: {"id": options.Args.Id}},
653 }
654 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{"Get-Depth: 2"}, h, h.GetParams)
655 if err != nil {
656 return err
657 } else if h.Status != nil && h.Status.Err() != nil {
658 return h.Status.Err()
659 }
660
661 d, err := dynamic.AsDynamicMessage(h.Response)
662 if err != nil {
663 return err
664 }
665
666 device := &model.Device{}
667 device.PopulateFrom(d)
668
669 outputFormat := CharReplacer.Replace(options.Format)
670 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000671 outputFormat = GetCommandOptionWithDefault("device-inspect", "format", DEFAULT_DEVICE_INSPECT_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700672 }
673 if options.Quiet {
674 outputFormat = "{{.Id}}"
675 }
676
677 result := CommandResult{
678 Format: format.Format(outputFormat),
679 OutputAs: toOutputType(options.OutputAs),
680 NameLimit: options.NameLimit,
681 Data: device,
682 }
683 GenerateOutput(&result)
684 return nil
685}
kesavand12cd8eb2020-01-20 22:25:22 -0500686
687/*Device Port Enable */
688func (options *DevicePortEnable) Execute(args []string) error {
689 conn, err := NewConnection()
690 if err != nil {
691 return err
692 }
693 defer conn.Close()
694
695 descriptor, method, err := GetMethod("device-port-enable")
696 if err != nil {
697 return err
698 }
699
700 h := &RpcEventHandler{
701 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["port"]: {"device_id": options.Args.Id, "port_no": options.Args.PortId}},
702 }
703 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
704 defer cancel()
705
706 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
707 if err != nil {
708 Error.Printf("Error enabling port number %v on device Id %s,err=%s\n", options.Args.PortId, options.Args.Id, ErrorToString(err))
709 return err
710 } else if h.Status != nil && h.Status.Err() != nil {
711 Error.Printf("Error enabling port number %v on device Id %s,err=%s\n", options.Args.PortId, options.Args.Id, ErrorToString(h.Status.Err()))
712 return h.Status.Err()
713 }
714
715 return nil
716}
717
718/*Device Port Disable */
719func (options *DevicePortDisable) Execute(args []string) error {
720 conn, err := NewConnection()
721 if err != nil {
722 return err
723 }
724 defer conn.Close()
725
726 descriptor, method, err := GetMethod("device-port-disable")
727 if err != nil {
728 return err
729 }
730 h := &RpcEventHandler{
731 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["port"]: {"device_id": options.Args.Id, "port_no": options.Args.PortId}},
732 }
733 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
734 defer cancel()
735
736 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
737 if err != nil {
738 Error.Printf("Error disabling port number %v on device Id %s,err=%s\n", options.Args.PortId, options.Args.Id, ErrorToString(err))
739 return err
740 } else if h.Status != nil && h.Status.Err() != nil {
741 Error.Printf("Error disabling port number %v on device Id %s,err=%s\n", options.Args.PortId, options.Args.Id, ErrorToString(h.Status.Err()))
742 return h.Status.Err()
743 }
744 return nil
745}
Dinesh Belwalkarc9aa6d82020-03-04 15:22:17 -0800746
747/*Device get Onu Distance */
748func (options *DeviceGetExtValue) Execute(args []string) error {
749 conn, err := NewConnection()
750 if err != nil {
751 return err
752 }
753 defer conn.Close()
754
755 descriptor, method, err := GetMethod("get-ext-value")
756 if err != nil {
757 return err
758 }
759
760 // TODO: support multiple flags (VOL-2946)
761 // TODO: a more extensible way to validate than a long if statement... (VOL-2946)
762 if (options.Args.Valueflag != "DISTANCE") && (options.Args.Valueflag != "EMPTY") {
763 return errors.New("ValueFlag must be either DISTANCE or EMPTY")
764 }
765
766 // value is an enum, so we need to map from an enum name to a value
767 valTypeDescriptor, err := descriptor.FindSymbol("common.ValueType")
768 if err != nil {
769 return err
770 }
771 valueTypeTypeDescriptor := valTypeDescriptor.GetFile().FindEnum("common.ValueType.Type")
772 eValue := valueTypeTypeDescriptor.FindValueByName(string(options.Args.Valueflag)).GetNumber()
773
774 h := &RpcEventHandler{
775 Fields: map[string]map[string]interface{}{ParamNames[GlobalConfig.ApiVersion]["ValueSpecifier"]: {"id": options.Args.Id, "value": eValue}},
776 }
777
778 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
779 defer cancel()
780
781 err = grpcurl.InvokeRPC(ctx, descriptor, conn, method, []string{}, h, h.GetParams)
782 if err != nil {
783 Error.Printf("Error getting value on device Id %s,err=%s\n", options.Args.Id, ErrorToString(err))
784 return err
785 } else if h.Status != nil && h.Status.Err() != nil {
786 Error.Printf("Error Error getting distance on device Id %s,err=%s\n", options.Args.Id, ErrorToString(h.Status.Err()))
787 return h.Status.Err()
788 }
789
790 d, err := dynamic.AsDynamicMessage(h.Response)
791 if err != nil {
792 return err
793 }
794
795 returnValues := &model.ReturnValues{}
796 returnValues.PopulateFrom(d)
797
798 returnRows := returnValues.GetKeyValuePairs(valueTypeTypeDescriptor.GetValues())
799
800 outputFormat := CharReplacer.Replace(options.Format)
801 if outputFormat == "" {
802 outputFormat = GetCommandOptionWithDefault("device-value-get", "format", DEFAULT_DEVICE_VALUE_GET_FORMAT)
803 }
804
805 result := CommandResult{
806 Format: format.Format(outputFormat),
807 OutputAs: toOutputType(options.OutputAs),
808 NameLimit: options.NameLimit,
809 Data: returnRows,
810 }
811 GenerateOutput(&result)
812 return nil
813}