networkdbdiagnostic.go 14 KB

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