main.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. //TODO: Harden. Add failover for every method and agent calls
  2. //TODO: Figure out why mongodb keeps failing (log rotation?)
  3. package main
  4. import (
  5. "log"
  6. "github.com/gravitl/netmaker/models"
  7. "github.com/gravitl/netmaker/controllers"
  8. "github.com/gravitl/netmaker/functions"
  9. "github.com/gravitl/netmaker/mongoconn"
  10. "github.com/gravitl/netmaker/config"
  11. "go.mongodb.org/mongo-driver/bson"
  12. "fmt"
  13. "time"
  14. "net/http"
  15. "errors"
  16. "io/ioutil"
  17. "os"
  18. "net"
  19. "context"
  20. "sync"
  21. "os/signal"
  22. service "github.com/gravitl/netmaker/controllers"
  23. nodepb "github.com/gravitl/netmaker/grpc"
  24. "google.golang.org/grpc"
  25. )
  26. var ServerGRPC string
  27. var PortGRPC string
  28. //Start MongoDB Connection and start API Request Handler
  29. func main() {
  30. log.Println("Server starting...")
  31. mongoconn.ConnectDatabase()
  32. var waitgroup sync.WaitGroup
  33. if config.Config.Server.AgentBackend {
  34. waitgroup.Add(1)
  35. go runGRPC(&waitgroup)
  36. }
  37. if config.Config.Server.RestBackend {
  38. waitgroup.Add(1)
  39. controller.HandleRESTRequests(&waitgroup)
  40. }
  41. if !config.Config.Server.RestBackend && !config.Config.Server.AgentBackend {
  42. fmt.Println("Oops! No Server Mode selected. Nothing being served.")
  43. }
  44. waitgroup.Wait()
  45. fmt.Println("Exiting now.")
  46. }
  47. func runGRPC(wg *sync.WaitGroup) {
  48. defer wg.Done()
  49. // Configure 'log' package to give file name and line number on eg. log.Fatal
  50. // Pipe flags to one another (log.LstdFLags = log.Ldate | log.Ltime)
  51. log.SetFlags(log.LstdFlags | log.Lshortfile)
  52. // Start our listener, 50051 is the default gRPC port
  53. grpcport := ":50051"
  54. if config.Config.Server.GrpcPort != "" {
  55. grpcport = ":" + config.Config.Server.GrpcPort
  56. }
  57. if os.Getenv("GRPC_PORT") != "" {
  58. grpcport = ":" + os.Getenv("GRPC_PORT")
  59. }
  60. PortGRPC = grpcport
  61. if os.Getenv("BACKEND_URL") == "" {
  62. if config.Config.Server.Host == "" {
  63. ServerGRPC, _ = getPublicIP()
  64. } else {
  65. ServerGRPC = config.Config.Server.Host
  66. }
  67. } else {
  68. ServerGRPC = os.Getenv("BACKEND_URL")
  69. }
  70. fmt.Println("GRPC Server set to: " + ServerGRPC)
  71. fmt.Println("GRPC Port set to: " + PortGRPC)
  72. var gconf models.GlobalConfig
  73. gconf.ServerGRPC = ServerGRPC
  74. gconf.PortGRPC = PortGRPC
  75. gconf.Name = "netmaker"
  76. err := setGlobalConfig(gconf)
  77. if err != nil {
  78. log.Fatalf("Unable to set global config: %v", err)
  79. }
  80. listener, err := net.Listen("tcp", grpcport)
  81. // Handle errors if any
  82. if err != nil {
  83. log.Fatalf("Unable to listen on port" + grpcport + ": %v", err)
  84. }
  85. s := grpc.NewServer(
  86. authServerUnaryInterceptor(),
  87. authServerStreamInterceptor(),
  88. )
  89. // Create NodeService type
  90. srv := &service.NodeServiceServer{}
  91. // Register the service with the server
  92. nodepb.RegisterNodeServiceServer(s, srv)
  93. srv.NodeDB = mongoconn.NodeDB
  94. // Start the server in a child routine
  95. go func() {
  96. if err := s.Serve(listener); err != nil {
  97. log.Fatalf("Failed to serve: %v", err)
  98. }
  99. }()
  100. fmt.Println("Agent Server succesfully started on port " + grpcport + " (gRPC)")
  101. // Right way to stop the server using a SHUTDOWN HOOK
  102. // Create a channel to receive OS signals
  103. c := make(chan os.Signal)
  104. // Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
  105. // Ignore other incoming signals
  106. signal.Notify(c, os.Interrupt)
  107. // Block main routine until a signal is received
  108. // As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
  109. <-c
  110. // After receiving CTRL+C Properly stop the server
  111. fmt.Println("Stopping the Agent server...")
  112. s.Stop()
  113. listener.Close()
  114. fmt.Println("Agent server closed..")
  115. fmt.Println("Closing MongoDB connection")
  116. mongoconn.Client.Disconnect(context.TODO())
  117. fmt.Println("MongoDB connection closed.")
  118. }
  119. func setGlobalConfig(globalconf models.GlobalConfig) (error) {
  120. collection := mongoconn.Client.Database("netmaker").Collection("config")
  121. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  122. _, err := functions.GetGlobalConfig()
  123. if err != nil {
  124. _, err := collection.InsertOne(ctx, globalconf)
  125. defer cancel()
  126. if err != nil {
  127. return err
  128. }
  129. } else {
  130. filter := bson.M{"name": "netmaker"}
  131. update := bson.D{
  132. {"$set", bson.D{
  133. {"servergrpc", globalconf.ServerGRPC},
  134. {"portgrpc", globalconf.PortGRPC},
  135. }},
  136. }
  137. err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&globalconf)
  138. }
  139. return nil
  140. }
  141. func getPublicIP() (string, error) {
  142. iplist := []string{"https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
  143. endpoint := ""
  144. var err error
  145. for _, ipserver := range iplist {
  146. resp, err := http.Get(ipserver)
  147. if err != nil {
  148. continue
  149. }
  150. defer resp.Body.Close()
  151. if resp.StatusCode == http.StatusOK {
  152. bodyBytes, err := ioutil.ReadAll(resp.Body)
  153. if err != nil {
  154. continue
  155. }
  156. endpoint = string(bodyBytes)
  157. break
  158. }
  159. }
  160. if err == nil && endpoint == "" {
  161. err = errors.New("Public Address Not Found.")
  162. }
  163. return endpoint, err
  164. }
  165. func authServerUnaryInterceptor() grpc.ServerOption {
  166. return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor)
  167. }
  168. func authServerStreamInterceptor() grpc.ServerOption {
  169. return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
  170. }