networkdbdiagnostic.go 14 KB

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