github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/client/cli/network/cli.go (about) 1 package cli 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "math" 8 "sort" 9 "strconv" 10 "strings" 11 12 "github.com/tickoalcantara12/micro/v3/client/cli/util" 13 "github.com/tickoalcantara12/micro/v3/cmd" 14 "github.com/tickoalcantara12/micro/v3/service/client" 15 "github.com/tickoalcantara12/micro/v3/service/context" 16 "github.com/olekukonko/tablewriter" 17 "github.com/urfave/cli/v2" 18 ) 19 20 func init() { 21 cmd.Register(&cli.Command{ 22 Name: "network", 23 Usage: "Manage the micro service network", 24 Subcommands: []*cli.Command{ 25 { 26 Name: "connect", 27 Usage: "connect to the network. specify nodes e.g connect ip:port", 28 Action: util.Print(networkConnect), 29 }, 30 { 31 Name: "connections", 32 Usage: "List the immediate connections to the network", 33 Action: util.Print(networkConnections), 34 }, 35 { 36 Name: "graph", 37 Usage: "Get the network graph", 38 Action: util.Print(networkGraph), 39 }, 40 { 41 Name: "nodes", 42 Usage: "List nodes in the network", 43 Action: util.Print(networkNodes), 44 }, 45 { 46 Name: "routes", 47 Usage: "List network routes", 48 Action: util.Print(networkRoutes), 49 Flags: []cli.Flag{ 50 &cli.StringFlag{ 51 Name: "service", 52 Usage: "Filter by service", 53 }, 54 &cli.StringFlag{ 55 Name: "address", 56 Usage: "Filter by address", 57 }, 58 &cli.StringFlag{ 59 Name: "gateway", 60 Usage: "Filter by gateway", 61 }, 62 &cli.StringFlag{ 63 Name: "router", 64 Usage: "Filter by router", 65 }, 66 &cli.StringFlag{ 67 Name: "network", 68 Usage: "Filter by network", 69 }, 70 }, 71 }, 72 { 73 Name: "services", 74 Usage: "Get the network services", 75 Action: util.Print(networkServices), 76 }, 77 }, 78 }) 79 } 80 81 func networkConnect(c *cli.Context, args []string) ([]byte, error) { 82 if len(args) == 0 { 83 return nil, nil 84 } 85 86 request := map[string]interface{}{ 87 "nodes": []interface{}{ 88 map[string]interface{}{ 89 "address": args[0], 90 }, 91 }, 92 } 93 94 var rsp map[string]interface{} 95 96 req := client.DefaultClient.NewRequest("network", "Network.Connect", request, client.WithContentType("application/json")) 97 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 98 if err != nil { 99 return nil, err 100 } 101 102 b, _ := json.MarshalIndent(rsp, "", "\t") 103 return b, nil 104 } 105 106 func networkConnections(c *cli.Context, args []string) ([]byte, error) { 107 108 request := map[string]interface{}{ 109 "depth": 1, 110 } 111 112 var rsp map[string]interface{} 113 114 req := client.DefaultClient.NewRequest("network", "Network.Graph", request, client.WithContentType("application/json")) 115 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 116 if err != nil { 117 return nil, err 118 } 119 120 if rsp["root"] == nil { 121 return nil, nil 122 } 123 124 peers := rsp["root"].(map[string]interface{})["peers"] 125 126 if peers == nil { 127 return nil, nil 128 } 129 130 b := bytes.NewBuffer(nil) 131 table := tablewriter.NewWriter(b) 132 table.SetHeader([]string{"NODE", "ADDRESS"}) 133 134 // root node 135 for _, n := range peers.([]interface{}) { 136 node := n.(map[string]interface{})["node"].(map[string]interface{}) 137 strEntry := []string{ 138 fmt.Sprintf("%s", node["id"]), 139 fmt.Sprintf("%s", node["address"]), 140 } 141 table.Append(strEntry) 142 } 143 144 // render table into b 145 table.SetAlignment(tablewriter.ALIGN_LEFT) 146 table.Render() 147 148 return b.Bytes(), nil 149 } 150 151 func networkGraph(c *cli.Context, args []string) ([]byte, error) { 152 153 var rsp map[string]interface{} 154 155 req := client.DefaultClient.NewRequest("network", "Network.Graph", map[string]interface{}{}, client.WithContentType("application/json")) 156 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 157 if err != nil { 158 return nil, err 159 } 160 161 b, _ := json.MarshalIndent(rsp, "", "\t") 162 return b, nil 163 } 164 165 func networkNodes(c *cli.Context, args []string) ([]byte, error) { 166 167 var rsp map[string]interface{} 168 169 // TODO: change to list nodes 170 req := client.DefaultClient.NewRequest("network", "Network.Nodes", map[string]interface{}{}, client.WithContentType("application/json")) 171 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 172 if err != nil { 173 return nil, err 174 } 175 176 // return if nil 177 if rsp["nodes"] == nil { 178 return nil, nil 179 } 180 181 b := bytes.NewBuffer(nil) 182 table := tablewriter.NewWriter(b) 183 table.SetHeader([]string{"ID", "ADDRESS"}) 184 185 // get nodes 186 187 if rsp["nodes"] != nil { 188 // root node 189 for _, n := range rsp["nodes"].([]interface{}) { 190 node := n.(map[string]interface{}) 191 strEntry := []string{ 192 fmt.Sprintf("%s", node["id"]), 193 fmt.Sprintf("%s", node["address"]), 194 } 195 table.Append(strEntry) 196 } 197 } 198 199 // render table into b 200 table.SetAlignment(tablewriter.ALIGN_LEFT) 201 table.Render() 202 203 return b.Bytes(), nil 204 } 205 206 func networkRoutes(c *cli.Context, args []string) ([]byte, error) { 207 208 query := map[string]string{} 209 210 for _, filter := range []string{"service", "address", "gateway", "router", "network"} { 211 if v := c.String(filter); len(v) > 0 { 212 query[filter] = v 213 } 214 } 215 216 request := map[string]interface{}{ 217 "query": query, 218 } 219 220 var rsp map[string]interface{} 221 222 req := client.DefaultClient.NewRequest("network", "Network.Routes", request, client.WithContentType("application/json")) 223 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 224 if err != nil { 225 return nil, err 226 } 227 228 if len(rsp) == 0 { 229 return []byte(``), nil 230 } 231 232 b := bytes.NewBuffer(nil) 233 table := tablewriter.NewWriter(b) 234 table.SetHeader([]string{"SERVICE", "ADDRESS", "GATEWAY", "ROUTER", "NETWORK", "METRIC", "LINK"}) 235 236 routes := rsp["routes"].([]interface{}) 237 238 val := func(v interface{}) string { 239 if v == nil { 240 return "" 241 } 242 return v.(string) 243 } 244 245 var sortedRoutes [][]string 246 247 for _, r := range routes { 248 route := r.(map[string]interface{}) 249 service := route["service"] 250 address := route["address"] 251 gateway := val(route["gateway"]) 252 router := route["router"] 253 network := route["network"] 254 link := route["link"] 255 metric := route["metric"] 256 257 var metInt int64 258 if metric != nil { 259 metInt, _ = strconv.ParseInt(route["metric"].(string), 10, 64) 260 } 261 262 // set max int64 metric to infinity 263 if metInt == math.MaxInt64 { 264 metric = "∞" 265 } else { 266 metric = fmt.Sprintf("%d", metInt) 267 } 268 269 sortedRoutes = append(sortedRoutes, []string{ 270 fmt.Sprintf("%s", service), 271 fmt.Sprintf("%s", address), 272 fmt.Sprintf("%s", gateway), 273 fmt.Sprintf("%s", router), 274 fmt.Sprintf("%s", network), 275 fmt.Sprintf("%s", metric), 276 fmt.Sprintf("%s", link), 277 }) 278 } 279 280 sort.Slice(sortedRoutes, func(i, j int) bool { return sortedRoutes[i][0] < sortedRoutes[j][0] }) 281 282 table.AppendBulk(sortedRoutes) 283 // render table into b 284 table.SetAlignment(tablewriter.ALIGN_LEFT) 285 table.Render() 286 287 return b.Bytes(), nil 288 } 289 290 func networkServices(c *cli.Context, args []string) ([]byte, error) { 291 292 var rsp map[string]interface{} 293 294 req := client.DefaultClient.NewRequest("network", "Network.Services", map[string]interface{}{}, client.WithContentType("application/json")) 295 err := client.DefaultClient.Call(context.DefaultContext, req, &rsp, client.WithAuthToken()) 296 if err != nil { 297 return nil, err 298 } 299 300 if len(rsp) == 0 || rsp["services"] == nil { 301 return []byte(``), nil 302 } 303 304 rspSrv := rsp["services"].([]interface{}) 305 306 var services []string 307 308 for _, service := range rspSrv { 309 services = append(services, service.(string)) 310 } 311 312 sort.Strings(services) 313 314 return []byte(strings.Join(services, "\n")), nil 315 }