hosts.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "time"
  8. "github.com/google/uuid"
  9. "github.com/gorilla/mux"
  10. "github.com/gravitl/netmaker/database"
  11. "github.com/gravitl/netmaker/logger"
  12. "github.com/gravitl/netmaker/logic"
  13. "github.com/gravitl/netmaker/models"
  14. "github.com/gravitl/netmaker/mq"
  15. "github.com/gravitl/netmaker/servercfg"
  16. "golang.org/x/crypto/bcrypt"
  17. "golang.org/x/exp/slog"
  18. )
  19. func hostHandlers(r *mux.Router) {
  20. r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).
  21. Methods(http.MethodGet)
  22. r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
  23. Methods(http.MethodPut)
  24. r.HandleFunc("/api/hosts/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHosts))).
  25. Methods(http.MethodPost)
  26. r.HandleFunc("/api/hosts/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHosts))).
  27. Methods(http.MethodPost)
  28. r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
  29. Methods(http.MethodPut)
  30. r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
  31. Methods(http.MethodPost)
  32. r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).
  33. Methods(http.MethodPut)
  34. r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).
  35. Methods(http.MethodDelete)
  36. r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).
  37. Methods(http.MethodPut)
  38. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).
  39. Methods(http.MethodPost)
  40. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).
  41. Methods(http.MethodDelete)
  42. r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
  43. r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).
  44. Methods(http.MethodGet)
  45. r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).
  46. Methods(http.MethodPost)
  47. r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
  48. Methods(http.MethodPut)
  49. r.HandleFunc("/api/v1/host/{hostid}/peer_info", Authorize(true, false, "host", http.HandlerFunc(getHostPeerInfo))).
  50. Methods(http.MethodGet)
  51. r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
  52. Methods(http.MethodDelete)
  53. r.HandleFunc("/api/v1/auth-register/host", socketHandler)
  54. r.HandleFunc("/api/v1/host/{hostid}/external_service_connector", logic.SecurityCheck(true, http.HandlerFunc(addExternalConnector))).
  55. Methods(http.MethodPost)
  56. }
  57. // @Summary Requests all the hosts to upgrade their version
  58. // @Router /api/hosts/upgrade [post]
  59. // @Tags Hosts
  60. // @Security oauth
  61. // @Param force query bool false "Force upgrade"
  62. // @Success 200 {string} string "upgrade all hosts request received"
  63. func upgradeHosts(w http.ResponseWriter, r *http.Request) {
  64. w.Header().Set("Content-Type", "application/json")
  65. action := models.Upgrade
  66. if r.URL.Query().Get("force") == "true" {
  67. action = models.ForceUpgrade
  68. }
  69. user := r.Header.Get("user")
  70. go func() {
  71. slog.Info("requesting all hosts to upgrade", "user", user)
  72. hosts, err := logic.GetAllHosts()
  73. if err != nil {
  74. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  75. return
  76. }
  77. for _, host := range hosts {
  78. go func(host models.Host) {
  79. hostUpdate := models.HostUpdate{
  80. Action: action,
  81. Host: host,
  82. }
  83. if err = mq.HostUpdate(&hostUpdate); err != nil {
  84. slog.Error("failed to request host to upgrade", "user", user, "host", host.ID.String(), "error", err)
  85. } else {
  86. slog.Info("host upgrade requested", "user", user, "host", host.ID.String())
  87. }
  88. }(host)
  89. }
  90. }()
  91. slog.Info("upgrade all hosts request received", "user", user)
  92. logic.ReturnSuccessResponse(w, r, "upgrade all hosts request received")
  93. }
  94. // @Summary Upgrade a host
  95. // @Router /api/hosts/{hostid}/upgrade [put]
  96. // @Tags Hosts
  97. // @Security oauth
  98. // @Param hostid path string true "Host ID"
  99. // @Param force query bool false "Force upgrade"
  100. // @Success 200 {string} string "passed message to upgrade host"
  101. // @Failure 500 {object} models.ErrorResponse
  102. // upgrade host is a handler to send upgrade message to a host
  103. func upgradeHost(w http.ResponseWriter, r *http.Request) {
  104. host, err := logic.GetHost(mux.Vars(r)["hostid"])
  105. if err != nil {
  106. slog.Error("failed to find host", "error", err)
  107. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
  108. return
  109. }
  110. action := models.Upgrade
  111. if r.URL.Query().Get("force") == "true" {
  112. action = models.ForceUpgrade
  113. }
  114. if err := mq.HostUpdate(&models.HostUpdate{Action: action, Host: *host}); err != nil {
  115. slog.Error("failed to upgrade host", "error", err)
  116. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  117. return
  118. }
  119. logic.ReturnSuccessResponse(w, r, "passed message to upgrade host")
  120. }
  121. // @Summary List all hosts
  122. // @Router /api/hosts [get]
  123. // @Tags Hosts
  124. // @Security oauth
  125. // @Success 200 {array} models.ApiHost
  126. // @Failure 500 {object} models.ErrorResponse
  127. func getHosts(w http.ResponseWriter, r *http.Request) {
  128. w.Header().Set("Content-Type", "application/json")
  129. currentHosts, err := logic.GetAllHosts()
  130. if err != nil {
  131. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  132. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  133. return
  134. }
  135. apiHosts := logic.GetAllHostsAPI(currentHosts[:])
  136. logger.Log(2, r.Header.Get("user"), "fetched all hosts")
  137. logic.SortApiHosts(apiHosts[:])
  138. w.WriteHeader(http.StatusOK)
  139. json.NewEncoder(w).Encode(apiHosts)
  140. }
  141. // @Summary Used by clients for "pull" command
  142. // @Router /api/v1/host [get]
  143. // @Tags Hosts
  144. // @Security oauth
  145. // @Success 200 {object} models.HostPull
  146. // @Failure 500 {object} models.ErrorResponse
  147. func pull(w http.ResponseWriter, r *http.Request) {
  148. hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
  149. if len(hostID) == 0 {
  150. logger.Log(0, "no host authorized to pull")
  151. logic.ReturnErrorResponse(
  152. w,
  153. r,
  154. logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"),
  155. )
  156. return
  157. }
  158. host, err := logic.GetHost(hostID)
  159. if err != nil {
  160. logger.Log(0, "no host found during pull", hostID)
  161. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  162. return
  163. }
  164. sendPeerUpdate := false
  165. for _, nodeID := range host.Nodes {
  166. node, err := logic.GetNodeByID(nodeID)
  167. if err != nil {
  168. slog.Error("failed to get node:", "id", node.ID, "error", err)
  169. continue
  170. }
  171. if node.FailedOverBy != uuid.Nil && r.URL.Query().Get("reset_failovered") == "true" {
  172. logic.ResetFailedOverPeer(&node)
  173. sendPeerUpdate = true
  174. }
  175. }
  176. if sendPeerUpdate {
  177. if err := mq.PublishPeerUpdate(false); err != nil {
  178. logger.Log(0, "fail to publish peer update: ", err.Error())
  179. }
  180. }
  181. allNodes, err := logic.GetAllNodes()
  182. if err != nil {
  183. logger.Log(0, "failed to get nodes: ", hostID)
  184. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  185. return
  186. }
  187. hPU, err := logic.GetPeerUpdateForHost("", host, allNodes, nil, nil)
  188. if err != nil {
  189. logger.Log(0, "could not pull peers for host", hostID, err.Error())
  190. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  191. return
  192. }
  193. serverConf := servercfg.GetServerInfo()
  194. key, keyErr := logic.RetrievePublicTrafficKey()
  195. if keyErr != nil {
  196. logger.Log(0, "error retrieving key:", keyErr.Error())
  197. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  198. return
  199. }
  200. serverConf.TrafficKey = key
  201. response := models.HostPull{
  202. Host: *host,
  203. Nodes: logic.GetHostNodes(host),
  204. ServerConfig: serverConf,
  205. Peers: hPU.Peers,
  206. PeerIDs: hPU.PeerIDs,
  207. HostNetworkInfo: hPU.HostNetworkInfo,
  208. EgressRoutes: hPU.EgressRoutes,
  209. FwUpdate: hPU.FwUpdate,
  210. ChangeDefaultGw: hPU.ChangeDefaultGw,
  211. DefaultGwIp: hPU.DefaultGwIp,
  212. IsInternetGw: hPU.IsInternetGw,
  213. EndpointDetection: servercfg.IsEndpointDetectionEnabled(),
  214. }
  215. logger.Log(1, hostID, "completed a pull")
  216. w.WriteHeader(http.StatusOK)
  217. json.NewEncoder(w).Encode(&response)
  218. }
  219. // @Summary Updates a Netclient host on Netmaker server
  220. // @Router /api/hosts/{hostid} [put]
  221. // @Tags Hosts
  222. // @Security oauth
  223. // @Param hostid path string true "Host ID"
  224. // @Param body body models.ApiHost true "New host data"
  225. // @Success 200 {object} models.ApiHost
  226. // @Failure 500 {object} models.ErrorResponse
  227. func updateHost(w http.ResponseWriter, r *http.Request) {
  228. var newHostData models.ApiHost
  229. err := json.NewDecoder(r.Body).Decode(&newHostData)
  230. if err != nil {
  231. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  232. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  233. return
  234. }
  235. // confirm host exists
  236. currHost, err := logic.GetHost(newHostData.ID)
  237. if err != nil {
  238. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  239. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  240. return
  241. }
  242. newHost := newHostData.ConvertAPIHostToNMHost(currHost)
  243. logic.UpdateHost(newHost, currHost) // update the in memory struct values
  244. if err = logic.UpsertHost(newHost); err != nil {
  245. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  246. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  247. return
  248. }
  249. // publish host update through MQ
  250. if err := mq.HostUpdate(&models.HostUpdate{
  251. Action: models.UpdateHost,
  252. Host: *newHost,
  253. }); err != nil {
  254. logger.Log(
  255. 0,
  256. r.Header.Get("user"),
  257. "failed to send host update: ",
  258. currHost.ID.String(),
  259. err.Error(),
  260. )
  261. }
  262. go func() {
  263. if err := mq.PublishPeerUpdate(false); err != nil {
  264. logger.Log(0, "fail to publish peer update: ", err.Error())
  265. }
  266. if newHost.Name != currHost.Name {
  267. if servercfg.IsDNSMode() {
  268. logic.SetDNS()
  269. }
  270. }
  271. }()
  272. apiHostData := newHost.ConvertNMHostToAPI()
  273. logger.Log(2, r.Header.Get("user"), "updated host", newHost.ID.String())
  274. w.WriteHeader(http.StatusOK)
  275. json.NewEncoder(w).Encode(apiHostData)
  276. }
  277. // @Summary Updates a Netclient host on Netmaker server
  278. // @Router /api/v1/fallback/host/{hostid} [put]
  279. // @Tags Hosts
  280. // @Security oauth
  281. // @Param hostid path string true "Host ID"
  282. // @Param body body models.HostUpdate true "Host update data"
  283. // @Success 200 {string} string "updated host data"
  284. // @Failure 500 {object} models.ErrorResponse
  285. func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
  286. var params = mux.Vars(r)
  287. hostid := params["hostid"]
  288. currentHost, err := logic.GetHost(hostid)
  289. if err != nil {
  290. slog.Error("error getting host", "id", hostid, "error", err)
  291. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  292. return
  293. }
  294. var sendPeerUpdate, sendHostUpdate bool
  295. var replacePeers bool
  296. var hostUpdate models.HostUpdate
  297. err = json.NewDecoder(r.Body).Decode(&hostUpdate)
  298. if err != nil {
  299. slog.Error("failed to update a host:", "user", r.Header.Get("user"), "error", err.Error(), "host", currentHost.Name)
  300. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  301. return
  302. }
  303. slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID, "action", hostUpdate.Action)
  304. switch hostUpdate.Action {
  305. case models.CheckIn:
  306. sendPeerUpdate = mq.HandleHostCheckin(&hostUpdate.Host, currentHost)
  307. case models.UpdateHost:
  308. if hostUpdate.Host.PublicKey != currentHost.PublicKey {
  309. //remove old peer entry
  310. replacePeers = true
  311. }
  312. sendPeerUpdate, sendHostUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
  313. err := logic.UpsertHost(currentHost)
  314. if err != nil {
  315. slog.Error("failed to update host", "id", currentHost.ID, "error", err)
  316. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  317. return
  318. }
  319. case models.UpdateMetrics:
  320. mq.UpdateMetricsFallBack(hostUpdate.Node.ID.String(), hostUpdate.NewMetrics)
  321. }
  322. if sendHostUpdate {
  323. fmt.Printf("Sending Host UPDATE: %+v\n", currentHost)
  324. mq.HostUpdate(&models.HostUpdate{
  325. Action: models.UpdateHost,
  326. Host: *currentHost,
  327. })
  328. }
  329. if sendPeerUpdate {
  330. err := mq.PublishPeerUpdate(replacePeers)
  331. if err != nil {
  332. slog.Error("failed to publish peer update", "error", err)
  333. }
  334. }
  335. logic.ReturnSuccessResponse(w, r, "updated host data")
  336. }
  337. // @Summary Deletes a Netclient host from Netmaker server
  338. // @Router /api/hosts/{hostid} [delete]
  339. // @Tags Hosts
  340. // @Security oauth
  341. // @Param hostid path string true "Host ID"
  342. // @Param force query bool false "Force delete"
  343. // @Success 200 {object} models.ApiHost
  344. // @Failure 500 {object} models.ErrorResponse
  345. func deleteHost(w http.ResponseWriter, r *http.Request) {
  346. var params = mux.Vars(r)
  347. hostid := params["hostid"]
  348. forceDelete := r.URL.Query().Get("force") == "true"
  349. // confirm host exists
  350. currHost, err := logic.GetHost(hostid)
  351. if err != nil {
  352. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  353. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  354. return
  355. }
  356. for _, nodeID := range currHost.Nodes {
  357. node, err := logic.GetNodeByID(nodeID)
  358. if err != nil {
  359. slog.Error("failed to get node", "nodeid", nodeID, "error", err)
  360. continue
  361. }
  362. var gwClients []models.ExtClient
  363. if node.IsIngressGateway {
  364. gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
  365. }
  366. go mq.PublishMqUpdatesForDeletedNode(node, false, gwClients)
  367. }
  368. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  369. // delete EMQX credentials for host
  370. if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil {
  371. slog.Error(
  372. "failed to remove host credentials from EMQX",
  373. "id",
  374. currHost.ID,
  375. "error",
  376. err,
  377. )
  378. }
  379. }
  380. if err = mq.HostUpdate(&models.HostUpdate{
  381. Action: models.DeleteHost,
  382. Host: *currHost,
  383. }); err != nil {
  384. logger.Log(
  385. 0,
  386. r.Header.Get("user"),
  387. "failed to send delete host update: ",
  388. currHost.ID.String(),
  389. err.Error(),
  390. )
  391. }
  392. if err = logic.RemoveHost(currHost, forceDelete); err != nil {
  393. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  394. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  395. return
  396. }
  397. apiHostData := currHost.ConvertNMHostToAPI()
  398. logger.Log(2, r.Header.Get("user"), "removed host", currHost.Name)
  399. w.WriteHeader(http.StatusOK)
  400. json.NewEncoder(w).Encode(apiHostData)
  401. }
  402. // @Summary To Add Host To Network
  403. // @Router /api/hosts/{hostid}/networks/{network} [post]
  404. // @Tags Hosts
  405. // @Security oauth
  406. // @Param hostid path string true "Host ID"
  407. // @Param network path string true "Network name"
  408. // @Success 200 {string} string "OK"
  409. // @Failure 500 {object} models.ErrorResponse
  410. func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
  411. var params = mux.Vars(r)
  412. hostid := params["hostid"]
  413. network := params["network"]
  414. if hostid == "" || network == "" {
  415. logic.ReturnErrorResponse(
  416. w,
  417. r,
  418. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  419. )
  420. return
  421. }
  422. // confirm host exists
  423. currHost, err := logic.GetHost(hostid)
  424. if err != nil {
  425. logger.Log(0, r.Header.Get("user"), "failed to find host:", hostid, err.Error())
  426. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  427. return
  428. }
  429. newNode, err := logic.UpdateHostNetwork(currHost, network, true)
  430. if err != nil {
  431. logger.Log(
  432. 0,
  433. r.Header.Get("user"),
  434. "failed to add host to network:",
  435. hostid,
  436. network,
  437. err.Error(),
  438. )
  439. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  440. return
  441. }
  442. logger.Log(1, "added new node", newNode.ID.String(), "to host", currHost.Name)
  443. if currHost.IsDefault {
  444. // make host failover
  445. logic.CreateFailOver(*newNode)
  446. // make host remote access gateway
  447. logic.CreateIngressGateway(network, newNode.ID.String(), models.IngressRequest{})
  448. }
  449. go func() {
  450. mq.HostUpdate(&models.HostUpdate{
  451. Action: models.JoinHostToNetwork,
  452. Host: *currHost,
  453. Node: *newNode,
  454. })
  455. mq.PublishPeerUpdate(false)
  456. if servercfg.IsDNSMode() {
  457. logic.SetDNS()
  458. }
  459. }()
  460. logger.Log(
  461. 2,
  462. r.Header.Get("user"),
  463. fmt.Sprintf("added host %s to network %s", currHost.Name, network),
  464. )
  465. w.WriteHeader(http.StatusOK)
  466. }
  467. // @Summary To Remove Host from Network
  468. // @Router /api/hosts/{hostid}/networks/{network} [delete]
  469. // @Tags Hosts
  470. // @Security oauth
  471. // @Param hostid path string true "Host ID"
  472. // @Param network path string true "Network name"
  473. // @Param force query bool false "Force delete"
  474. // @Success 200 {string} string "OK"
  475. // @Failure 500 {object} models.ErrorResponse
  476. func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
  477. var params = mux.Vars(r)
  478. hostid := params["hostid"]
  479. network := params["network"]
  480. forceDelete := r.URL.Query().Get("force") == "true"
  481. if hostid == "" || network == "" {
  482. logic.ReturnErrorResponse(
  483. w,
  484. r,
  485. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  486. )
  487. return
  488. }
  489. // confirm host exists
  490. currHost, err := logic.GetHost(hostid)
  491. if err != nil {
  492. if database.IsEmptyRecord(err) {
  493. // check if there is any daemon nodes that needs to be deleted
  494. node, err := logic.GetNodeByHostRef(hostid, network)
  495. if err != nil {
  496. slog.Error(
  497. "couldn't get node for host",
  498. "hostid",
  499. hostid,
  500. "network",
  501. network,
  502. "error",
  503. err,
  504. )
  505. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  506. return
  507. }
  508. if err = logic.DeleteNodeByID(&node); err != nil {
  509. slog.Error("failed to force delete daemon node",
  510. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  511. logic.ReturnErrorResponse(
  512. w,
  513. r,
  514. logic.FormatError(
  515. fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
  516. "internal",
  517. ),
  518. )
  519. return
  520. }
  521. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  522. return
  523. }
  524. logger.Log(0, r.Header.Get("user"), "failed to find host:", err.Error())
  525. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  526. return
  527. }
  528. node, err := logic.UpdateHostNetwork(currHost, network, false)
  529. if err != nil {
  530. if node == nil && forceDelete {
  531. // force cleanup the node
  532. node, err := logic.GetNodeByHostRef(hostid, network)
  533. if err != nil {
  534. slog.Error(
  535. "couldn't get node for host",
  536. "hostid",
  537. hostid,
  538. "network",
  539. network,
  540. "error",
  541. err,
  542. )
  543. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  544. return
  545. }
  546. if err = logic.DeleteNodeByID(&node); err != nil {
  547. slog.Error("failed to force delete daemon node",
  548. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  549. logic.ReturnErrorResponse(
  550. w,
  551. r,
  552. logic.FormatError(
  553. fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
  554. "internal",
  555. ),
  556. )
  557. return
  558. }
  559. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  560. return
  561. }
  562. logger.Log(
  563. 0,
  564. r.Header.Get("user"),
  565. "failed to remove host from network:",
  566. hostid,
  567. network,
  568. err.Error(),
  569. )
  570. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  571. return
  572. }
  573. var gwClients []models.ExtClient
  574. if node.IsIngressGateway {
  575. gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
  576. }
  577. logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
  578. if err := logic.DeleteNode(node, forceDelete); err != nil {
  579. logic.ReturnErrorResponse(
  580. w,
  581. r,
  582. logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
  583. )
  584. return
  585. }
  586. go func() {
  587. mq.PublishMqUpdatesForDeletedNode(*node, true, gwClients)
  588. if servercfg.IsDNSMode() {
  589. logic.SetDNS()
  590. }
  591. }()
  592. logger.Log(
  593. 2,
  594. r.Header.Get("user"),
  595. fmt.Sprintf("removed host %s from network %s", currHost.Name, network),
  596. )
  597. w.WriteHeader(http.StatusOK)
  598. }
  599. // @Summary To Fetch Auth Token for a Host
  600. // @Router /api/hosts/adm/authenticate [post]
  601. // @Tags Auth
  602. // @Accept json
  603. // @Param body body models.AuthParams true "Authentication parameters"
  604. // @Success 200 {object} models.SuccessResponse
  605. // @Failure 400 {object} models.ErrorResponse
  606. // @Failure 401 {object} models.ErrorResponse
  607. // @Failure 500 {object} models.ErrorResponse
  608. func authenticateHost(response http.ResponseWriter, request *http.Request) {
  609. var authRequest models.AuthParams
  610. var errorResponse = models.ErrorResponse{
  611. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  612. }
  613. decoder := json.NewDecoder(request.Body)
  614. decoderErr := decoder.Decode(&authRequest)
  615. defer request.Body.Close()
  616. if decoderErr != nil {
  617. errorResponse.Code = http.StatusBadRequest
  618. errorResponse.Message = decoderErr.Error()
  619. logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
  620. decoderErr.Error())
  621. logic.ReturnErrorResponse(response, request, errorResponse)
  622. return
  623. }
  624. errorResponse.Code = http.StatusBadRequest
  625. if authRequest.ID == "" {
  626. errorResponse.Message = "W1R3: ID can't be empty"
  627. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  628. logic.ReturnErrorResponse(response, request, errorResponse)
  629. return
  630. } else if authRequest.Password == "" {
  631. errorResponse.Message = "W1R3: Password can't be empty"
  632. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  633. logic.ReturnErrorResponse(response, request, errorResponse)
  634. return
  635. }
  636. host, err := logic.GetHost(authRequest.ID)
  637. if err != nil {
  638. errorResponse.Code = http.StatusBadRequest
  639. errorResponse.Message = err.Error()
  640. logger.Log(0, request.Header.Get("user"),
  641. "error retrieving host: ", authRequest.ID, err.Error())
  642. logic.ReturnErrorResponse(response, request, errorResponse)
  643. return
  644. }
  645. err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password))
  646. if err != nil {
  647. errorResponse.Code = http.StatusUnauthorized
  648. errorResponse.Message = "unauthorized"
  649. logger.Log(0, request.Header.Get("user"),
  650. "error validating user password: ", err.Error())
  651. logic.ReturnErrorResponse(response, request, errorResponse)
  652. return
  653. }
  654. tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "")
  655. if tokenString == "" {
  656. errorResponse.Code = http.StatusUnauthorized
  657. errorResponse.Message = "unauthorized"
  658. logger.Log(0, request.Header.Get("user"),
  659. fmt.Sprintf("%s: %v", errorResponse.Message, err))
  660. logic.ReturnErrorResponse(response, request, errorResponse)
  661. return
  662. }
  663. var successResponse = models.SuccessResponse{
  664. Code: http.StatusOK,
  665. Message: "W1R3: Host " + authRequest.ID + " Authorized",
  666. Response: models.SuccessfulLoginResponse{
  667. AuthToken: tokenString,
  668. ID: authRequest.ID,
  669. },
  670. }
  671. successJSONResponse, jsonError := json.Marshal(successResponse)
  672. if jsonError != nil {
  673. errorResponse.Code = http.StatusBadRequest
  674. errorResponse.Message = err.Error()
  675. logger.Log(0, request.Header.Get("user"),
  676. "error marshalling resp: ", err.Error())
  677. logic.ReturnErrorResponse(response, request, errorResponse)
  678. return
  679. }
  680. go func() {
  681. // Create EMQX creds
  682. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  683. if err := mq.GetEmqxHandler().CreateEmqxUser(host.ID.String(), authRequest.Password); err != nil {
  684. slog.Error("failed to create host credentials for EMQX: ", err.Error())
  685. }
  686. }
  687. }()
  688. response.WriteHeader(http.StatusOK)
  689. response.Header().Set("Content-Type", "application/json")
  690. response.Write(successJSONResponse)
  691. }
  692. // @Summary Send signal to peer
  693. // @Router /api/v1/host/{hostid}/signalpeer [post]
  694. // @Tags Hosts
  695. // @Security oauth
  696. // @Param hostid path string true "Host ID"
  697. // @Param body body models.Signal true "Signal data"
  698. // @Success 200 {object} models.Signal
  699. // @Failure 400 {object} models.ErrorResponse
  700. func signalPeer(w http.ResponseWriter, r *http.Request) {
  701. var params = mux.Vars(r)
  702. hostid := params["hostid"]
  703. // confirm host exists
  704. _, err := logic.GetHost(hostid)
  705. if err != nil {
  706. logger.Log(0, r.Header.Get("user"), "failed to get host:", err.Error())
  707. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  708. return
  709. }
  710. var signal models.Signal
  711. w.Header().Set("Content-Type", "application/json")
  712. err = json.NewDecoder(r.Body).Decode(&signal)
  713. if err != nil {
  714. logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
  715. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  716. return
  717. }
  718. if signal.ToHostPubKey == "" {
  719. msg := "insufficient data to signal peer"
  720. logger.Log(0, r.Header.Get("user"), msg)
  721. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest"))
  722. return
  723. }
  724. signal.IsPro = servercfg.IsPro
  725. peerHost, err := logic.GetHost(signal.ToHostID)
  726. if err != nil {
  727. logic.ReturnErrorResponse(
  728. w,
  729. r,
  730. logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"),
  731. )
  732. return
  733. }
  734. err = mq.HostUpdate(&models.HostUpdate{
  735. Action: models.SignalHost,
  736. Host: *peerHost,
  737. Signal: signal,
  738. })
  739. if err != nil {
  740. logic.ReturnErrorResponse(
  741. w,
  742. r,
  743. logic.FormatError(
  744. errors.New("failed to publish signal to peer: "+err.Error()),
  745. "badrequest",
  746. ),
  747. )
  748. return
  749. }
  750. w.WriteHeader(http.StatusOK)
  751. json.NewEncoder(w).Encode(signal)
  752. }
  753. // @Summary Update keys for all hosts
  754. // @Router /api/hosts/keys [put]
  755. // @Tags Hosts
  756. // @Security oauth
  757. // @Success 200 {string} string "OK"
  758. // @Failure 400 {object} models.ErrorResponse
  759. func updateAllKeys(w http.ResponseWriter, r *http.Request) {
  760. var errorResponse = models.ErrorResponse{}
  761. w.Header().Set("Content-Type", "application/json")
  762. hosts, err := logic.GetAllHosts()
  763. if err != nil {
  764. errorResponse.Code = http.StatusBadRequest
  765. errorResponse.Message = err.Error()
  766. logger.Log(0, r.Header.Get("user"),
  767. "error retrieving hosts ", err.Error())
  768. logic.ReturnErrorResponse(w, r, errorResponse)
  769. return
  770. }
  771. go func() {
  772. hostUpdate := models.HostUpdate{}
  773. hostUpdate.Action = models.UpdateKeys
  774. for _, host := range hosts {
  775. hostUpdate.Host = host
  776. logger.Log(2, "updating host", host.ID.String(), " for a key update")
  777. if err = mq.HostUpdate(&hostUpdate); err != nil {
  778. logger.Log(
  779. 0,
  780. "failed to send update to node during a network wide key update",
  781. host.ID.String(),
  782. err.Error(),
  783. )
  784. }
  785. }
  786. }()
  787. logger.Log(2, r.Header.Get("user"), "updated keys for all hosts")
  788. w.WriteHeader(http.StatusOK)
  789. }
  790. // @Summary Update keys for a host
  791. // @Router /api/hosts/{hostid}/keys [put]
  792. // @Tags Hosts
  793. // @Security oauth
  794. // @Param hostid path string true "Host ID"
  795. // @Success 200 {string} string "OK"
  796. // @Failure 400 {object} models.ErrorResponse
  797. func updateKeys(w http.ResponseWriter, r *http.Request) {
  798. var errorResponse = models.ErrorResponse{}
  799. w.Header().Set("Content-Type", "application/json")
  800. var params = mux.Vars(r)
  801. hostid := params["hostid"]
  802. host, err := logic.GetHost(hostid)
  803. if err != nil {
  804. logger.Log(0, "failed to retrieve host", hostid, err.Error())
  805. errorResponse.Code = http.StatusBadRequest
  806. errorResponse.Message = err.Error()
  807. logger.Log(0, r.Header.Get("user"),
  808. "error retrieving hosts ", err.Error())
  809. logic.ReturnErrorResponse(w, r, errorResponse)
  810. return
  811. }
  812. go func() {
  813. hostUpdate := models.HostUpdate{
  814. Action: models.UpdateKeys,
  815. Host: *host,
  816. }
  817. if err = mq.HostUpdate(&hostUpdate); err != nil {
  818. logger.Log(0, "failed to send host key update", host.ID.String(), err.Error())
  819. }
  820. }()
  821. logger.Log(2, r.Header.Get("user"), "updated key on host", host.Name)
  822. w.WriteHeader(http.StatusOK)
  823. }
  824. // @Summary Requests all the hosts to pull
  825. // @Router /api/hosts/sync [post]
  826. // @Tags Hosts
  827. // @Security oauth
  828. // @Success 200 {string} string "sync all hosts request received"
  829. func syncHosts(w http.ResponseWriter, r *http.Request) {
  830. w.Header().Set("Content-Type", "application/json")
  831. user := r.Header.Get("user")
  832. go func() {
  833. slog.Info("requesting all hosts to sync", "user", user)
  834. hosts, err := logic.GetAllHosts()
  835. if err != nil {
  836. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  837. return
  838. }
  839. for _, host := range hosts {
  840. go func(host models.Host) {
  841. hostUpdate := models.HostUpdate{
  842. Action: models.RequestPull,
  843. Host: host,
  844. }
  845. if err = mq.HostUpdate(&hostUpdate); err != nil {
  846. slog.Error("failed to request host to sync", "user", user, "host", host.ID.String(), "error", err)
  847. } else {
  848. slog.Info("host sync requested", "user", user, "host", host.ID.String())
  849. }
  850. }(host)
  851. time.Sleep(time.Millisecond * 100)
  852. }
  853. }()
  854. slog.Info("sync all hosts request received", "user", user)
  855. logic.ReturnSuccessResponse(w, r, "sync all hosts request received")
  856. }
  857. // @Summary Requests a host to pull
  858. // @Router /api/hosts/{hostid}/sync [post]
  859. // @Tags Hosts
  860. // @Security oauth
  861. // @Param hostid path string true "Host ID"
  862. // @Success 200 {string} string "OK"
  863. // @Failure 400 {object} models.ErrorResponse
  864. func syncHost(w http.ResponseWriter, r *http.Request) {
  865. hostId := mux.Vars(r)["hostid"]
  866. var errorResponse = models.ErrorResponse{}
  867. w.Header().Set("Content-Type", "application/json")
  868. host, err := logic.GetHost(hostId)
  869. if err != nil {
  870. slog.Error("failed to retrieve host", "user", r.Header.Get("user"), "error", err)
  871. errorResponse.Code = http.StatusBadRequest
  872. errorResponse.Message = err.Error()
  873. logic.ReturnErrorResponse(w, r, errorResponse)
  874. return
  875. }
  876. go func() {
  877. hostUpdate := models.HostUpdate{
  878. Action: models.RequestPull,
  879. Host: *host,
  880. }
  881. if err = mq.HostUpdate(&hostUpdate); err != nil {
  882. slog.Error("failed to send host pull request", "host", host.ID.String(), "error", err)
  883. }
  884. }()
  885. slog.Info("requested host pull", "user", r.Header.Get("user"), "host", host.ID.String())
  886. w.WriteHeader(http.StatusOK)
  887. }
  888. // @Summary Deletes all EMQX hosts
  889. // @Router /api/emqx/hosts [delete]
  890. // @Tags Hosts
  891. // @Security oauth
  892. // @Success 200 {string} string "deleted hosts data on emqx"
  893. // @Failure 500 {object} models.ErrorResponse
  894. func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
  895. currentHosts, err := logic.GetAllHosts()
  896. if err != nil {
  897. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  898. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  899. return
  900. }
  901. for _, host := range currentHosts {
  902. // delete EMQX credentials for host
  903. if err := mq.GetEmqxHandler().DeleteEmqxUser(host.ID.String()); err != nil {
  904. slog.Error("failed to remove host credentials from EMQX", "id", host.ID, "error", err)
  905. }
  906. }
  907. err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName())
  908. if err != nil {
  909. slog.Error(
  910. "failed to remove server credentials from EMQX",
  911. "user",
  912. servercfg.GetMqUserName(),
  913. "error",
  914. err,
  915. )
  916. }
  917. logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
  918. }
  919. // @Summary Fetches host peerinfo
  920. // @Router /api/host/{hostid}/peer_info [get]
  921. // @Tags Hosts
  922. // @Security oauth
  923. // @Param hostid path string true "Host ID"
  924. // @Success 200 {object} models.SuccessResponse
  925. // @Failure 500 {object} models.ErrorResponse
  926. func getHostPeerInfo(w http.ResponseWriter, r *http.Request) {
  927. hostId := mux.Vars(r)["hostid"]
  928. var errorResponse = models.ErrorResponse{}
  929. host, err := logic.GetHost(hostId)
  930. if err != nil {
  931. slog.Error("failed to retrieve host", "error", err)
  932. errorResponse.Code = http.StatusBadRequest
  933. errorResponse.Message = err.Error()
  934. logic.ReturnErrorResponse(w, r, errorResponse)
  935. return
  936. }
  937. peerInfo, err := logic.GetHostPeerInfo(host)
  938. if err != nil {
  939. slog.Error("failed to retrieve host peerinfo", "error", err)
  940. errorResponse.Code = http.StatusBadRequest
  941. errorResponse.Message = err.Error()
  942. logic.ReturnErrorResponse(w, r, errorResponse)
  943. return
  944. }
  945. logic.ReturnSuccessResponseWithJson(w, r, peerInfo, "fetched host peer info")
  946. }
  947. // @Summary create external connector
  948. // @Router /api/hosts/{hostid}/sync [post]
  949. // @Tags Hosts
  950. // @Security oauth
  951. // @Param hostid path string true "Host ID"
  952. // @Success 200 {string} string "OK"
  953. // @Failure 400 {object} models.ErrorResponse
  954. func addExternalConnector(w http.ResponseWriter, r *http.Request) {
  955. hostId := mux.Vars(r)["hostid"]
  956. var errorResponse = models.ErrorResponse{}
  957. w.Header().Set("Content-Type", "application/json")
  958. host, err := logic.GetHost(hostId)
  959. if err != nil {
  960. slog.Error("failed to retrieve host", "user", r.Header.Get("user"), "error", err)
  961. errorResponse.Code = http.StatusBadRequest
  962. errorResponse.Message = err.Error()
  963. logic.ReturnErrorResponse(w, r, errorResponse)
  964. return
  965. }
  966. var egressServices = []string{}
  967. err = json.NewDecoder(r.Body).Decode(&egressServices)
  968. if err != nil {
  969. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  970. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  971. return
  972. }
  973. host.EgressServices = make(map[string][]models.EgressIPNat)
  974. for _, egressServiceI := range egressServices {
  975. host.EgressServices[egressServiceI] = []models.EgressIPNat{}
  976. }
  977. logic.UpsertHost(host)
  978. go func() {
  979. hostUpdate := models.HostUpdate{
  980. Action: models.DiscoverEgressIps,
  981. Host: *host,
  982. }
  983. if err = mq.HostUpdate(&hostUpdate); err != nil {
  984. slog.Error("failed to send host pull request", "host", host.ID.String(), "error", err)
  985. }
  986. }()
  987. logic.ReturnSuccessResponseWithJson(w, r, host, "updates host service connectors")
  988. }