github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/cmd/diagnostic/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"flag"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"os"
    13  	"strings"
    14  
    15  	"github.com/docker/libnetwork"
    16  	"github.com/docker/libnetwork/diagnostic"
    17  	"github.com/docker/libnetwork/drivers/overlay"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  const (
    22  	readyPath    = "http://%s:%d/ready"
    23  	joinNetwork  = "http://%s:%d/joinnetwork?nid=%s"
    24  	leaveNetwork = "http://%s:%d/leavenetwork?nid=%s"
    25  	clusterPeers = "http://%s:%d/clusterpeers?json"
    26  	networkPeers = "http://%s:%d/networkpeers?nid=%s&json"
    27  	dumpTable    = "http://%s:%d/gettable?nid=%s&tname=%s&json"
    28  	deleteEntry  = "http://%s:%d/deleteentry?nid=%s&tname=%s&key=%s&json"
    29  )
    30  
    31  func httpIsOk(body io.ReadCloser) {
    32  	b, err := ioutil.ReadAll(body)
    33  	if err != nil {
    34  		logrus.Fatalf("Failed the body parse %s", err)
    35  	}
    36  	if !strings.Contains(string(b), "OK") {
    37  		logrus.Fatalf("Server not ready %s", b)
    38  	}
    39  	body.Close()
    40  }
    41  
    42  func main() {
    43  	ipPtr := flag.String("ip", "127.0.0.1", "ip address")
    44  	portPtr := flag.Int("port", 2000, "port")
    45  	networkPtr := flag.String("net", "", "target network")
    46  	tablePtr := flag.String("t", "", "table to process <sd/overlay>")
    47  	remediatePtr := flag.Bool("r", false, "perform remediation deleting orphan entries")
    48  	joinPtr := flag.Bool("a", false, "join/leave network")
    49  	verbosePtr := flag.Bool("v", false, "verbose output")
    50  
    51  	flag.Parse()
    52  
    53  	if *verbosePtr {
    54  		logrus.SetLevel(logrus.DebugLevel)
    55  	}
    56  
    57  	if _, ok := os.LookupEnv("DIND_CLIENT"); !ok && *joinPtr {
    58  		logrus.Fatal("you are not using the client in docker in docker mode, the use of the -a flag can be disruptive, " +
    59  			"please remove it (doc:https://github.com/docker/libnetwork/blob/master/cmd/diagnostic/README.md)")
    60  	}
    61  
    62  	logrus.Infof("Connecting to %s:%d checking ready", *ipPtr, *portPtr)
    63  	resp, err := http.Get(fmt.Sprintf(readyPath, *ipPtr, *portPtr))
    64  	if err != nil {
    65  		logrus.WithError(err).Fatalf("The connection failed")
    66  	}
    67  	httpIsOk(resp.Body)
    68  
    69  	clusterPeers := fetchNodePeers(*ipPtr, *portPtr, "")
    70  	var networkPeers map[string]string
    71  	var joinedNetwork bool
    72  	if *networkPtr != "" {
    73  		if *joinPtr {
    74  			logrus.Infof("Joining the network:%q", *networkPtr)
    75  			resp, err = http.Get(fmt.Sprintf(joinNetwork, *ipPtr, *portPtr, *networkPtr))
    76  			if err != nil {
    77  				logrus.WithError(err).Fatalf("Failed joining the network")
    78  			}
    79  			httpIsOk(resp.Body)
    80  			joinedNetwork = true
    81  		}
    82  
    83  		networkPeers = fetchNodePeers(*ipPtr, *portPtr, *networkPtr)
    84  		if len(networkPeers) == 0 {
    85  			logrus.Warnf("There is no peer on network %q, check the network ID, and verify that is the non truncated version", *networkPtr)
    86  		}
    87  	}
    88  
    89  	switch *tablePtr {
    90  	case "sd":
    91  		fetchTable(*ipPtr, *portPtr, *networkPtr, "endpoint_table", clusterPeers, networkPeers, *remediatePtr)
    92  	case "overlay":
    93  		fetchTable(*ipPtr, *portPtr, *networkPtr, "overlay_peer_table", clusterPeers, networkPeers, *remediatePtr)
    94  	}
    95  
    96  	if joinedNetwork {
    97  		logrus.Infof("Leaving the network:%q", *networkPtr)
    98  		resp, err = http.Get(fmt.Sprintf(leaveNetwork, *ipPtr, *portPtr, *networkPtr))
    99  		if err != nil {
   100  			logrus.WithError(err).Fatalf("Failed leaving the network")
   101  		}
   102  		httpIsOk(resp.Body)
   103  	}
   104  }
   105  
   106  func fetchNodePeers(ip string, port int, network string) map[string]string {
   107  	if network == "" {
   108  		logrus.Infof("Fetch cluster peers")
   109  	} else {
   110  		logrus.Infof("Fetch peers network:%q", network)
   111  	}
   112  
   113  	var path string
   114  	if network != "" {
   115  		path = fmt.Sprintf(networkPeers, ip, port, network)
   116  	} else {
   117  		path = fmt.Sprintf(clusterPeers, ip, port)
   118  	}
   119  
   120  	resp, err := http.Get(path)
   121  	if err != nil {
   122  		logrus.WithError(err).Fatalf("Failed fetching path")
   123  	}
   124  	defer resp.Body.Close()
   125  	body, err := ioutil.ReadAll(resp.Body)
   126  	if err != nil {
   127  		logrus.WithError(err).Fatalf("Failed the body parse")
   128  	}
   129  
   130  	output := diagnostic.HTTPResult{Details: &diagnostic.TablePeersResult{}}
   131  	err = json.Unmarshal(body, &output)
   132  	if err != nil {
   133  		logrus.WithError(err).Fatalf("Failed the json unmarshalling")
   134  	}
   135  
   136  	logrus.Debugf("Parsing JSON response")
   137  	result := make(map[string]string, output.Details.(*diagnostic.TablePeersResult).Length)
   138  	for _, v := range output.Details.(*diagnostic.TablePeersResult).Elements {
   139  		logrus.Debugf("name:%s ip:%s", v.Name, v.IP)
   140  		result[v.Name] = v.IP
   141  	}
   142  	return result
   143  }
   144  
   145  func fetchTable(ip string, port int, network, tableName string, clusterPeers, networkPeers map[string]string, remediate bool) {
   146  	logrus.Infof("Fetch %s table and check owners", tableName)
   147  	resp, err := http.Get(fmt.Sprintf(dumpTable, ip, port, network, tableName))
   148  	if err != nil {
   149  		logrus.WithError(err).Fatalf("Failed fetching endpoint table")
   150  	}
   151  	defer resp.Body.Close()
   152  	body, err := ioutil.ReadAll(resp.Body)
   153  	if err != nil {
   154  		logrus.WithError(err).Fatalf("Failed the body parse")
   155  	}
   156  
   157  	output := diagnostic.HTTPResult{Details: &diagnostic.TableEndpointsResult{}}
   158  	err = json.Unmarshal(body, &output)
   159  	if err != nil {
   160  		logrus.WithError(err).Fatalf("Failed the json unmarshalling")
   161  	}
   162  
   163  	logrus.Debug("Parsing data structures")
   164  	var orphanKeys []string
   165  	for _, v := range output.Details.(*diagnostic.TableEndpointsResult).Elements {
   166  		decoded, err := base64.StdEncoding.DecodeString(v.Value)
   167  		if err != nil {
   168  			logrus.WithError(err).Errorf("Failed decoding entry")
   169  			continue
   170  		}
   171  		switch tableName {
   172  		case "endpoint_table":
   173  			var elem libnetwork.EndpointRecord
   174  			elem.Unmarshal(decoded)
   175  			logrus.Debugf("key:%s value:%+v owner:%s", v.Key, elem, v.Owner)
   176  		case "overlay_peer_table":
   177  			var elem overlay.PeerRecord
   178  			elem.Unmarshal(decoded)
   179  			logrus.Debugf("key:%s value:%+v owner:%s", v.Key, elem, v.Owner)
   180  		}
   181  
   182  		if _, ok := networkPeers[v.Owner]; !ok {
   183  			logrus.Warnf("The element with key:%s does not belong to any node on this network", v.Key)
   184  			orphanKeys = append(orphanKeys, v.Key)
   185  		}
   186  		if _, ok := clusterPeers[v.Owner]; !ok {
   187  			logrus.Warnf("The element with key:%s does not belong to any node on this cluster", v.Key)
   188  		}
   189  	}
   190  
   191  	if len(orphanKeys) > 0 && remediate {
   192  		logrus.Warnf("The following keys:%v results as orphan, do you want to proceed with the deletion (this operation is irreversible)? [Yes/No]", orphanKeys)
   193  		reader := bufio.NewReader(os.Stdin)
   194  		text, _ := reader.ReadString('\n')
   195  		text = strings.Replace(text, "\n", "", -1)
   196  		if strings.Compare(text, "Yes") == 0 {
   197  			for _, k := range orphanKeys {
   198  				resp, err := http.Get(fmt.Sprintf(deleteEntry, ip, port, network, tableName, k))
   199  				if err != nil {
   200  					logrus.WithError(err).Errorf("Failed deleting entry k:%s", k)
   201  					break
   202  				}
   203  				resp.Body.Close()
   204  			}
   205  		} else {
   206  			logrus.Infof("Deletion skipped")
   207  		}
   208  	}
   209  }