networkdbdiagnostic.go 13 KB

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