diff --git a/cmd/pola/README.md b/cmd/pola/README.md index b3cc704..2cabb81 100644 --- a/cmd/pola/README.md +++ b/cmd/pola/README.md @@ -114,7 +114,7 @@ json formatted response ] ``` -### pola lsp list -f _filepath_ +### pola lsp add -f _filepath_ Create a new SR-Policy yaml input format @@ -137,4 +137,153 @@ json formatted response { "status": "success" } +``` + +### pola ted \[-j\] +Displays the ted managed by polad. + +json formatted response +``` +{ + "ted": [ + { + "asn": 65000, + "hostname": "host1", + "isisAreaId": "490000", + "links": [ + { + "adjSid": 17, + "localIP": "10.0.1.1", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.1.2", + "remoteNode": "0000.0aff.0003" + }, + { + "adjSid": 18, + "localIP": "10.0.0.1", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.0.2", + "remoteNode": "0000.0aff.0002" + } + ], + "prefixes": [ + { + "prefix": "10.0.1.0/30" + }, + { + "prefix": "10.0.0.0/30" + }, + { + "prefix": "10.255.0.1/32", + "sidIndex": 1 + } + ], + "routerId": "0000.0aff.0001", + "srgbBegin": 16000, + "srgbEnd": 24000 + }, + { + "asn": 65000, + "hostname": "host2", + "isisAreaId": "490000", + "links": [ + { + "adjSid": 17, + "localIP": "10.0.1.2", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.1.1", + "remoteNode": "0000.0aff.0001" + }, + { + "adjSid": 16, + "localIP": "10.0.2.2", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.2.1", + "remoteNode": "0000.0aff.0002" + } + ], + "prefixes": [ + { + "prefix": "10.255.0.3/32", + "sidIndex": 3 + }, + { + "prefix": "10.0.2.0/30" + }, + { + "prefix": "10.0.1.0/30" + } + ], + "routerId": "0000.0aff.0003", + "srgbBegin": 16000, + "srgbEnd": 24000 + }, + { + "asn": 65000, + "hostname": "host3", + "isisAreaId": "490000", + "links": [ + { + "adjSid": 24001, + "localIP": "10.0.0.2", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.0.1", + "remoteNode": "0000.0aff.0001" + }, + { + "adjSid": 24003, + "localIP": "10.0.2.1", + "metrics": [ + { + "type": "IGP", + "value": 10 + } + ], + "remoteIP": "10.0.2.2", + "remoteNode": "0000.0aff.0201" + } + ], + "prefixes": [ + { + "prefix": "10.0.2.0/30" + }, + { + "prefix": "10.0.0.0/30" + }, + { + "prefix": "10.255.0.2/32", + "sidIndex": 2 + } + ], + "routerId": "0000.0aff.0002", + "srgbBegin": 16000, + "srgbEnd": 24000 + } + ] +} ``` \ No newline at end of file diff --git a/cmd/pola/grpc_client.go b/cmd/pola/grpc_client.go index 65c4d00..683f74a 100644 --- a/cmd/pola/grpc_client.go +++ b/cmd/pola/grpc_client.go @@ -13,6 +13,7 @@ import ( "github.com/golang/protobuf/ptypes/empty" pb "github.com/nttcom/pola/api/grpc" + "github.com/nttcom/pola/internal/pkg/table" ) type lspInfo struct { @@ -29,7 +30,7 @@ func getPeerAddrList(client pb.PceServiceClient) ([]net.IP, error) { var empty empty.Empty ret, err := client.GetPeerAddrList(ctx, &empty) if err != nil { - return nil, errors.New("Could not get Peer Address.\n") + return nil, errors.New("could not get Peer Address") } var peerAddrList []net.IP for _, peerAddr := range ret.GetPeerAddrs() { @@ -44,7 +45,7 @@ func getlspList(client pb.PceServiceClient) ([]lspInfo, error) { var empty empty.Empty ret, err := client.GetLspList(ctx, &empty) if err != nil { - return nil, errors.New("Could not get Lsp List.\n") + return nil, errors.New("could not get Lsp List") } lspList := []lspInfo{} for _, lsp := range ret.GetLsps() { @@ -73,3 +74,64 @@ func createLsp(client pb.PceServiceClient, lspData *pb.LspData) error { } return nil } + +func getTed(client pb.PceServiceClient) (*table.LsTed, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + var empty empty.Empty + ret, err := client.GetTed(ctx, &empty) + if err != nil { + return nil, errors.New("could not get Peer Address") + } + ted := &table.LsTed{ + Id: 1, + Nodes: map[uint32]map[string]*table.LsNode{}, + } + + for _, node := range ret.GetLsNodes() { + lsNode := table.NewLsNode(node.GetAsn(), node.GetRouterId()) + lsNode.Hostname = node.GetHostname() + lsNode.IsisAreaId = node.GetIsisAreaId() + lsNode.SrgbBegin = node.GetSrgbBegin() + lsNode.SrgbEnd = node.GetSrgbEnd() + + if _, ok := ted.Nodes[lsNode.Asn]; !ok { + ted.Nodes[lsNode.Asn] = map[string]*table.LsNode{} + } + ted.Nodes[lsNode.Asn][lsNode.RouterId] = lsNode + } + + for _, node := range ret.GetLsNodes() { + for _, link := range node.LsLinks { + lsLink := table.NewLsLink(ted.Nodes[link.LocalAsn][link.LocalRouterId], ted.Nodes[link.RemoteAsn][link.RemoteRouterId]) + lsLink.AdjSid = link.GetAdjSid() + lsLink.LocalIP = net.ParseIP(link.GetLocalIp()) + lsLink.RemoteIP = net.ParseIP(link.GetRemoteIp()) + for _, metricInfo := range link.GetMetrics() { + var metric *table.Metric + switch metricInfo.GetType().String() { + case "IGP": + metric = table.NewMetric(table.IGP_METRIC, metricInfo.GetValue()) + case "TE": + metric = table.NewMetric(table.IGP_METRIC, metricInfo.GetValue()) + case "DELAY": + metric = table.NewMetric(table.IGP_METRIC, metricInfo.GetValue()) + case "HOPCOUNT": + metric = table.NewMetric(table.IGP_METRIC, metricInfo.GetValue()) + default: + return nil, errors.New("unknown metric type") + } + lsLink.Metrics = append(lsLink.Metrics, metric) + } + ted.Nodes[node.GetAsn()][node.GetRouterId()].Links = append(ted.Nodes[node.GetAsn()][node.GetRouterId()].Links, lsLink) + } + + for _, prefix := range node.LsPrefixes { + lsPrefix := table.NewLsPrefixV4(ted.Nodes[node.GetAsn()][node.GetRouterId()]) + _, lsPrefix.Prefix, _ = net.ParseCIDR(prefix.GetPrefix()) + lsPrefix.SidIndex = prefix.GetSidIndex() + ted.Nodes[node.GetAsn()][node.GetRouterId()].Prefixes = append(ted.Nodes[node.GetAsn()][node.GetRouterId()].Prefixes, lsPrefix) + } + } + return ted, nil +} diff --git a/cmd/pola/main.go b/cmd/pola/main.go index e81b55d..13fbafe 100644 --- a/cmd/pola/main.go +++ b/cmd/pola/main.go @@ -14,6 +14,7 @@ import ( func main() { if len(os.Args) > 1 && os.Args[1] == "--version" { fmt.Printf("alpha release.\n") + return } if err := newRootCmd().Execute(); err != nil { diff --git a/cmd/pola/root.go b/cmd/pola/root.go index cda5574..1e0f77c 100644 --- a/cmd/pola/root.go +++ b/cmd/pola/root.go @@ -18,7 +18,7 @@ func newRootCmd() *cobra.Command { rootCmd := &cobra.Command{ Use: "pola", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.Dial("localhost:50052", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { conn.Close() return err @@ -31,6 +31,6 @@ func newRootCmd() *cobra.Command { cmd.HelpFunc()(cmd, args) }, } - rootCmd.AddCommand(newSessionCmd(), newLspCmd()) + rootCmd.AddCommand(newSessionCmd(), newLspCmd(), newTedCmd()) return rootCmd } diff --git a/cmd/pola/ted.go b/cmd/pola/ted.go new file mode 100644 index 0000000..ee31d8f --- /dev/null +++ b/cmd/pola/ted.go @@ -0,0 +1,105 @@ +// Copyright (c) 2022 NTT Communications Corporation +// +// This software is released under the MIT License. +// see https://github.com/nttcom/pola/blob/main/LICENSE + +package main + +import ( + "encoding/json" + "fmt" + + "github.com/spf13/cobra" +) + +func newTedCmd() *cobra.Command { + + tedCmd := &cobra.Command{ + Use: "ted", + RunE: func(cmd *cobra.Command, args []string) error { + jsonFmt, err := cmd.Flags().GetBool("json") + if err != nil { + return err + } + if err := showTed(jsonFmt); err != nil { + return err + } + return nil + }, + } + + tedCmd.Flags().BoolP("json", "j", false, "output json format") + return tedCmd +} + +func showTed(jsonFlag bool) error { + ted, err := getTed(client) + if err != nil { + return err + } + if jsonFlag { + // output json format + nodes := []map[string]interface{}{} + for _, as := range ted.Nodes { + for _, node := range as { + tmpNode := map[string]interface{}{ // TODO: Fix format according to readme + "asn": node.Asn, + "routerId": node.RouterId, + "isisAreaId": node.IsisAreaId, + "hostname": node.Hostname, + "srgbBegin": node.SrgbBegin, + "srgbEnd": node.SrgbEnd, + "prefixes": []map[string]interface{}{}, + "links": []map[string]interface{}{}, + } + links := []map[string]interface{}{} + for _, link := range node.Links { + tmpLink := map[string]interface{}{ + "localIP": link.LocalIP.String(), + "remoteIP": link.RemoteIP.String(), + "remoteNode": link.RemoteNode.RouterId, + "metrics": []map[string]interface{}{}, + "adjSid": link.AdjSid, + } + metrics := []map[string]interface{}{} + for _, metric := range link.Metrics { + tmpMetric := map[string]interface{}{ + "type": metric.Type.String(), + "value": metric.Value, + } + metrics = append(metrics, tmpMetric) + } + tmpLink["metrics"] = metrics + links = append(links, tmpLink) + } + tmpNode["links"] = links + prefixes := []map[string]interface{}{} + for _, prefix := range node.Prefixes { + tmpPrefix := map[string]interface{}{ + "prefix": prefix.Prefix.String(), + } + if prefix.SidIndex != 0 { + tmpPrefix["sidIndex"] = prefix.SidIndex + } + prefixes = append(prefixes, tmpPrefix) + } + tmpNode["prefixes"] = prefixes + nodes = append(nodes, tmpNode) + + } + } + output_map := map[string]interface{}{ + "ted": nodes, + } + output_json, err := json.Marshal(output_map) + if err != nil { + return err + } + fmt.Printf("%+v\n", string(output_json)) + + } else { + //output user-friendly format + ted.ShowTed() + } + return nil +}