github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/libnetwork/networkdb/networkdbdiagnostic.go (about)

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