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  }