github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/networkdb/networkdbdiagnostic.go (about)

     1  package networkdb
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"net/http"
     8  	"strings"
     9  
    10  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/diagnostic"
    11  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/internal/caller"
    12  	"github.com/containerd/log"
    13  )
    14  
    15  const (
    16  	missingParameter = "missing parameter"
    17  	dbNotAvailable   = "database not available"
    18  )
    19  
    20  // NetDbPaths2Func TODO
    21  var NetDbPaths2Func = map[string]diagnostic.HTTPHandlerFunc{
    22  	"/join":         dbJoin,
    23  	"/networkpeers": dbPeers,
    24  	"/clusterpeers": dbClusterPeers,
    25  	"/joinnetwork":  dbJoinNetwork,
    26  	"/leavenetwork": dbLeaveNetwork,
    27  	"/createentry":  dbCreateEntry,
    28  	"/updateentry":  dbUpdateEntry,
    29  	"/deleteentry":  dbDeleteEntry,
    30  	"/getentry":     dbGetEntry,
    31  	"/gettable":     dbGetTable,
    32  	"/networkstats": dbNetworkStats,
    33  }
    34  
    35  func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) {
    36  	_ = r.ParseForm()
    37  	diagnostic.DebugHTTPForm(r)
    38  	_, json := diagnostic.ParseHTTPFormOptions(r)
    39  
    40  	// audit logs
    41  	logger := log.G(context.TODO()).WithFields(log.Fields{
    42  		"component": "diagnostic",
    43  		"remoteIP":  r.RemoteAddr,
    44  		"method":    caller.Name(0),
    45  		"url":       r.URL.String(),
    46  	})
    47  	logger.Info("join cluster")
    48  
    49  	if len(r.Form["members"]) < 1 {
    50  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?members=ip1,ip2,...", r.URL.Path))
    51  		logger.Error("join cluster failed, wrong input")
    52  		diagnostic.HTTPReply(w, rsp, json)
    53  		return
    54  	}
    55  
    56  	nDB, ok := ctx.(*NetworkDB)
    57  	if ok {
    58  		err := nDB.Join(strings.Split(r.Form["members"][0], ","))
    59  		if err != nil {
    60  			rsp := diagnostic.FailCommand(fmt.Errorf("%s error in the DB join %s", r.URL.Path, err))
    61  			logger.WithError(err).Error("join cluster failed")
    62  			diagnostic.HTTPReply(w, rsp, json)
    63  			return
    64  		}
    65  
    66  		logger.Info("join cluster done")
    67  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
    68  		return
    69  	}
    70  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
    71  }
    72  
    73  func dbPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
    74  	_ = r.ParseForm()
    75  	diagnostic.DebugHTTPForm(r)
    76  	_, json := diagnostic.ParseHTTPFormOptions(r)
    77  
    78  	// audit logs
    79  	logger := log.G(context.TODO()).WithFields(log.Fields{
    80  		"component": "diagnostic",
    81  		"remoteIP":  r.RemoteAddr,
    82  		"method":    caller.Name(0),
    83  		"url":       r.URL.String(),
    84  	})
    85  	logger.Info("network peers")
    86  
    87  	if len(r.Form["nid"]) < 1 {
    88  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=test", r.URL.Path))
    89  		logger.Error("network peers failed, wrong input")
    90  		diagnostic.HTTPReply(w, rsp, json)
    91  		return
    92  	}
    93  
    94  	nDB, ok := ctx.(*NetworkDB)
    95  	if ok {
    96  		peers := nDB.Peers(r.Form["nid"][0])
    97  		rsp := &diagnostic.TableObj{Length: len(peers)}
    98  		for i, peerInfo := range peers {
    99  			if peerInfo.IP == "unknown" {
   100  				rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: "orphan-" + peerInfo.Name, IP: peerInfo.IP})
   101  			} else {
   102  				rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP})
   103  			}
   104  		}
   105  		logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network peers done")
   106  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json)
   107  		return
   108  	}
   109  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   110  }
   111  
   112  func dbClusterPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   113  	_ = r.ParseForm()
   114  	diagnostic.DebugHTTPForm(r)
   115  	_, json := diagnostic.ParseHTTPFormOptions(r)
   116  
   117  	// audit logs
   118  	logger := log.G(context.TODO()).WithFields(log.Fields{
   119  		"component": "diagnostic",
   120  		"remoteIP":  r.RemoteAddr,
   121  		"method":    caller.Name(0),
   122  		"url":       r.URL.String(),
   123  	})
   124  	logger.Info("cluster peers")
   125  
   126  	nDB, ok := ctx.(*NetworkDB)
   127  	if ok {
   128  		peers := nDB.ClusterPeers()
   129  		rsp := &diagnostic.TableObj{Length: len(peers)}
   130  		for i, peerInfo := range peers {
   131  			rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP})
   132  		}
   133  		logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("cluster peers done")
   134  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json)
   135  		return
   136  	}
   137  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   138  }
   139  
   140  func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   141  	_ = r.ParseForm()
   142  	diagnostic.DebugHTTPForm(r)
   143  	unsafe, json := diagnostic.ParseHTTPFormOptions(r)
   144  
   145  	// audit logs
   146  	logger := log.G(context.TODO()).WithFields(log.Fields{
   147  		"component": "diagnostic",
   148  		"remoteIP":  r.RemoteAddr,
   149  		"method":    caller.Name(0),
   150  		"url":       r.URL.String(),
   151  	})
   152  	logger.Info("create entry")
   153  
   154  	if len(r.Form["tname"]) < 1 ||
   155  		len(r.Form["nid"]) < 1 ||
   156  		len(r.Form["key"]) < 1 ||
   157  		len(r.Form["value"]) < 1 {
   158  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
   159  		logger.Error("create entry failed, wrong input")
   160  		diagnostic.HTTPReply(w, rsp, json)
   161  		return
   162  	}
   163  
   164  	tname := r.Form["tname"][0]
   165  	nid := r.Form["nid"][0]
   166  	key := r.Form["key"][0]
   167  	value := r.Form["value"][0]
   168  	decodedValue := []byte(value)
   169  	if !unsafe {
   170  		var err error
   171  		decodedValue, err = base64.StdEncoding.DecodeString(value)
   172  		if err != nil {
   173  			logger.WithError(err).Error("create entry failed")
   174  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   175  			return
   176  		}
   177  	}
   178  
   179  	nDB, ok := ctx.(*NetworkDB)
   180  	if ok {
   181  		if err := nDB.CreateEntry(tname, nid, key, decodedValue); err != nil {
   182  			rsp := diagnostic.FailCommand(err)
   183  			diagnostic.HTTPReply(w, rsp, json)
   184  			logger.WithError(err).Error("create entry failed")
   185  			return
   186  		}
   187  		logger.Info("create entry done")
   188  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
   189  		return
   190  	}
   191  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   192  }
   193  
   194  func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   195  	_ = r.ParseForm()
   196  	diagnostic.DebugHTTPForm(r)
   197  	unsafe, json := diagnostic.ParseHTTPFormOptions(r)
   198  
   199  	// audit logs
   200  	logger := log.G(context.TODO()).WithFields(log.Fields{
   201  		"component": "diagnostic",
   202  		"remoteIP":  r.RemoteAddr,
   203  		"method":    caller.Name(0),
   204  		"url":       r.URL.String(),
   205  	})
   206  	logger.Info("update entry")
   207  
   208  	if len(r.Form["tname"]) < 1 ||
   209  		len(r.Form["nid"]) < 1 ||
   210  		len(r.Form["key"]) < 1 ||
   211  		len(r.Form["value"]) < 1 {
   212  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
   213  		logger.Error("update entry failed, wrong input")
   214  		diagnostic.HTTPReply(w, rsp, json)
   215  		return
   216  	}
   217  
   218  	tname := r.Form["tname"][0]
   219  	nid := r.Form["nid"][0]
   220  	key := r.Form["key"][0]
   221  	value := r.Form["value"][0]
   222  	decodedValue := []byte(value)
   223  	if !unsafe {
   224  		var err error
   225  		decodedValue, err = base64.StdEncoding.DecodeString(value)
   226  		if err != nil {
   227  			logger.WithError(err).Error("update entry failed")
   228  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   229  			return
   230  		}
   231  	}
   232  
   233  	nDB, ok := ctx.(*NetworkDB)
   234  	if ok {
   235  		if err := nDB.UpdateEntry(tname, nid, key, decodedValue); err != nil {
   236  			logger.WithError(err).Error("update entry failed")
   237  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   238  			return
   239  		}
   240  		logger.Info("update entry done")
   241  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
   242  		return
   243  	}
   244  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   245  }
   246  
   247  func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   248  	_ = r.ParseForm()
   249  	diagnostic.DebugHTTPForm(r)
   250  	_, json := diagnostic.ParseHTTPFormOptions(r)
   251  
   252  	// audit logs
   253  	logger := log.G(context.TODO()).WithFields(log.Fields{
   254  		"component": "diagnostic",
   255  		"remoteIP":  r.RemoteAddr,
   256  		"method":    caller.Name(0),
   257  		"url":       r.URL.String(),
   258  	})
   259  	logger.Info("delete entry")
   260  
   261  	if len(r.Form["tname"]) < 1 ||
   262  		len(r.Form["nid"]) < 1 ||
   263  		len(r.Form["key"]) < 1 {
   264  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
   265  		logger.Error("delete entry failed, wrong input")
   266  		diagnostic.HTTPReply(w, rsp, json)
   267  		return
   268  	}
   269  
   270  	tname := r.Form["tname"][0]
   271  	nid := r.Form["nid"][0]
   272  	key := r.Form["key"][0]
   273  
   274  	nDB, ok := ctx.(*NetworkDB)
   275  	if ok {
   276  		err := nDB.DeleteEntry(tname, nid, key)
   277  		if err != nil {
   278  			logger.WithError(err).Error("delete entry failed")
   279  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   280  			return
   281  		}
   282  		logger.Info("delete entry done")
   283  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
   284  		return
   285  	}
   286  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   287  }
   288  
   289  func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   290  	_ = r.ParseForm()
   291  	diagnostic.DebugHTTPForm(r)
   292  	unsafe, json := diagnostic.ParseHTTPFormOptions(r)
   293  
   294  	// audit logs
   295  	logger := log.G(context.TODO()).WithFields(log.Fields{
   296  		"component": "diagnostic",
   297  		"remoteIP":  r.RemoteAddr,
   298  		"method":    caller.Name(0),
   299  		"url":       r.URL.String(),
   300  	})
   301  	logger.Info("get entry")
   302  
   303  	if len(r.Form["tname"]) < 1 ||
   304  		len(r.Form["nid"]) < 1 ||
   305  		len(r.Form["key"]) < 1 {
   306  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
   307  		logger.Error("get entry failed, wrong input")
   308  		diagnostic.HTTPReply(w, rsp, json)
   309  		return
   310  	}
   311  
   312  	tname := r.Form["tname"][0]
   313  	nid := r.Form["nid"][0]
   314  	key := r.Form["key"][0]
   315  
   316  	nDB, ok := ctx.(*NetworkDB)
   317  	if ok {
   318  		value, err := nDB.GetEntry(tname, nid, key)
   319  		if err != nil {
   320  			logger.WithError(err).Error("get entry failed")
   321  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   322  			return
   323  		}
   324  
   325  		var encodedValue string
   326  		if unsafe {
   327  			encodedValue = string(value)
   328  		} else {
   329  			encodedValue = base64.StdEncoding.EncodeToString(value)
   330  		}
   331  
   332  		rsp := &diagnostic.TableEntryObj{Key: key, Value: encodedValue}
   333  		logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get entry done")
   334  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json)
   335  		return
   336  	}
   337  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   338  }
   339  
   340  func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   341  	_ = r.ParseForm()
   342  	diagnostic.DebugHTTPForm(r)
   343  	_, json := diagnostic.ParseHTTPFormOptions(r)
   344  
   345  	// audit logs
   346  	logger := log.G(context.TODO()).WithFields(log.Fields{
   347  		"component": "diagnostic",
   348  		"remoteIP":  r.RemoteAddr,
   349  		"method":    caller.Name(0),
   350  		"url":       r.URL.String(),
   351  	})
   352  	logger.Info("join network")
   353  
   354  	if len(r.Form["nid"]) < 1 {
   355  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
   356  		logger.Error("join network failed, wrong input")
   357  		diagnostic.HTTPReply(w, rsp, json)
   358  		return
   359  	}
   360  
   361  	nid := r.Form["nid"][0]
   362  
   363  	nDB, ok := ctx.(*NetworkDB)
   364  	if ok {
   365  		if err := nDB.JoinNetwork(nid); err != nil {
   366  			logger.WithError(err).Error("join network failed")
   367  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   368  			return
   369  		}
   370  		logger.Info("join network done")
   371  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
   372  		return
   373  	}
   374  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   375  }
   376  
   377  func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   378  	_ = r.ParseForm()
   379  	diagnostic.DebugHTTPForm(r)
   380  	_, json := diagnostic.ParseHTTPFormOptions(r)
   381  
   382  	// audit logs
   383  	logger := log.G(context.TODO()).WithFields(log.Fields{
   384  		"component": "diagnostic",
   385  		"remoteIP":  r.RemoteAddr,
   386  		"method":    caller.Name(0),
   387  		"url":       r.URL.String(),
   388  	})
   389  	logger.Info("leave network")
   390  
   391  	if len(r.Form["nid"]) < 1 {
   392  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
   393  		logger.Error("leave network failed, wrong input")
   394  		diagnostic.HTTPReply(w, rsp, json)
   395  		return
   396  	}
   397  
   398  	nid := r.Form["nid"][0]
   399  
   400  	nDB, ok := ctx.(*NetworkDB)
   401  	if ok {
   402  		if err := nDB.LeaveNetwork(nid); err != nil {
   403  			logger.WithError(err).Error("leave network failed")
   404  			diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json)
   405  			return
   406  		}
   407  		logger.Info("leave network done")
   408  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json)
   409  		return
   410  	}
   411  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   412  }
   413  
   414  func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   415  	_ = r.ParseForm()
   416  	diagnostic.DebugHTTPForm(r)
   417  	unsafe, json := diagnostic.ParseHTTPFormOptions(r)
   418  
   419  	// audit logs
   420  	logger := log.G(context.TODO()).WithFields(log.Fields{
   421  		"component": "diagnostic",
   422  		"remoteIP":  r.RemoteAddr,
   423  		"method":    caller.Name(0),
   424  		"url":       r.URL.String(),
   425  	})
   426  	logger.Info("get table")
   427  
   428  	if len(r.Form["tname"]) < 1 ||
   429  		len(r.Form["nid"]) < 1 {
   430  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id", r.URL.Path))
   431  		logger.Error("get table failed, wrong input")
   432  		diagnostic.HTTPReply(w, rsp, json)
   433  		return
   434  	}
   435  
   436  	tname := r.Form["tname"][0]
   437  	nid := r.Form["nid"][0]
   438  
   439  	nDB, ok := ctx.(*NetworkDB)
   440  	if ok {
   441  		table := nDB.GetTableByNetwork(tname, nid)
   442  		rsp := &diagnostic.TableObj{Length: len(table)}
   443  		i := 0
   444  		for k, v := range table {
   445  			var encodedValue string
   446  			if unsafe {
   447  				encodedValue = string(v.Value)
   448  			} else {
   449  				encodedValue = base64.StdEncoding.EncodeToString(v.Value)
   450  			}
   451  			rsp.Elements = append(rsp.Elements,
   452  				&diagnostic.TableEntryObj{
   453  					Index: i,
   454  					Key:   k,
   455  					Value: encodedValue,
   456  					Owner: v.owner,
   457  				})
   458  			i++
   459  		}
   460  		logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get table done")
   461  		diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json)
   462  		return
   463  	}
   464  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   465  }
   466  
   467  func dbNetworkStats(ctx interface{}, w http.ResponseWriter, r *http.Request) {
   468  	_ = r.ParseForm()
   469  	diagnostic.DebugHTTPForm(r)
   470  	_, json := diagnostic.ParseHTTPFormOptions(r)
   471  
   472  	// audit logs
   473  	logger := log.G(context.TODO()).WithFields(log.Fields{
   474  		"component": "diagnostic",
   475  		"remoteIP":  r.RemoteAddr,
   476  		"method":    caller.Name(0),
   477  		"url":       r.URL.String(),
   478  	})
   479  	logger.Info("network stats")
   480  
   481  	if len(r.Form["nid"]) < 1 {
   482  		rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=test", r.URL.Path))
   483  		logger.Error("network stats failed, wrong input")
   484  		diagnostic.HTTPReply(w, rsp, json)
   485  		return
   486  	}
   487  
   488  	nDB, ok := ctx.(*NetworkDB)
   489  	if ok {
   490  		nDB.RLock()
   491  		networks := nDB.networks[nDB.config.NodeID]
   492  		network, ok := networks[r.Form["nid"][0]]
   493  
   494  		entries := -1
   495  		qLen := -1
   496  		if ok {
   497  			entries = int(network.entriesNumber.Load())
   498  			qLen = network.tableBroadcasts.NumQueued()
   499  		}
   500  		nDB.RUnlock()
   501  
   502  		rsp := diagnostic.CommandSucceed(&diagnostic.NetworkStatsResult{Entries: entries, QueueLen: qLen})
   503  		logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network stats done")
   504  		diagnostic.HTTPReply(w, rsp, json)
   505  		return
   506  	}
   507  	diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json)
   508  }