apiserver.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package apiserver
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "time"
  9. "github.com/crowdsecurity/crowdsec/pkg/apiserver/controllers"
  10. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  11. "github.com/crowdsecurity/crowdsec/pkg/database"
  12. "github.com/crowdsecurity/crowdsec/pkg/types"
  13. "github.com/gin-gonic/gin"
  14. "github.com/go-co-op/gocron"
  15. "github.com/pkg/errors"
  16. log "github.com/sirupsen/logrus"
  17. "gopkg.in/tomb.v2"
  18. )
  19. var (
  20. keyLength = 32
  21. )
  22. type APIServer struct {
  23. URL string
  24. TLS *csconfig.TLSCfg
  25. dbClient *database.Client
  26. logFile string
  27. ctx context.Context
  28. controller *controllers.Controller
  29. flushScheduler *gocron.Scheduler
  30. router *gin.Engine
  31. httpServer *http.Server
  32. apic *apic
  33. httpServerTomb tomb.Tomb
  34. }
  35. func NewServer(config *csconfig.LocalApiServerCfg) (*APIServer, error) {
  36. var flushScheduler *gocron.Scheduler
  37. dbClient, err := database.NewClient(config.DbConfig)
  38. if err != nil {
  39. return &APIServer{}, fmt.Errorf("unable to init database client: %s", err)
  40. }
  41. if config.DbConfig.Flush != nil {
  42. flushScheduler, err = dbClient.StartFlushScheduler(config.DbConfig.Flush)
  43. if err != nil {
  44. return &APIServer{}, err
  45. }
  46. }
  47. logFile := ""
  48. if config.LogDir != "" && config.LogMedia == "file" {
  49. logFile = fmt.Sprintf("%s/crowdsec_api.log", config.LogDir)
  50. }
  51. if log.GetLevel() < log.DebugLevel {
  52. gin.SetMode(gin.ReleaseMode)
  53. }
  54. log.Debugf("starting router, logging to %s", logFile)
  55. router := gin.New()
  56. /* See https://github.com/gin-gonic/gin/pull/2474:
  57. Gin does not handle safely X-Forwarded-For or X-Real-IP.
  58. We do not trust them by default, but the user can opt-in
  59. if they host LAPI behind a trusted proxy which sanitize
  60. X-Forwarded-For and X-Real-IP.
  61. */
  62. router.ForwardedByClientIP = config.UseForwardedForHeaders
  63. /*The logger that will be used by handlers*/
  64. clog := log.New()
  65. if err := types.ConfigureLogger(clog); err != nil {
  66. return nil, errors.Wrap(err, "while configuring gin logger")
  67. }
  68. if config.LogLevel != nil {
  69. clog.SetLevel(*config.LogLevel)
  70. }
  71. gin.DefaultErrorWriter = clog.Writer()
  72. // Logging to a file.
  73. if logFile != "" {
  74. file, err := os.Create(logFile)
  75. if err != nil {
  76. return &APIServer{}, errors.Wrapf(err, "creating api access log file: %s", logFile)
  77. }
  78. gin.DefaultWriter = io.MultiWriter(file, os.Stdout)
  79. }
  80. router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
  81. return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
  82. param.ClientIP,
  83. param.TimeStamp.Format(time.RFC1123),
  84. param.Method,
  85. param.Path,
  86. param.Request.Proto,
  87. param.StatusCode,
  88. param.Latency,
  89. param.Request.UserAgent(),
  90. param.ErrorMessage,
  91. )
  92. }))
  93. router.NoRoute(func(c *gin.Context) {
  94. c.JSON(http.StatusNotFound, gin.H{"message": "Page or Method not found"})
  95. return
  96. })
  97. router.Use(gin.Recovery())
  98. controller := &controllers.Controller{
  99. DBClient: dbClient,
  100. Ectx: context.Background(),
  101. Router: router,
  102. Profiles: config.Profiles,
  103. Log: clog,
  104. }
  105. var apiClient *apic
  106. if config.OnlineClient != nil {
  107. log.Printf("Loading CAPI pusher")
  108. apiClient, err = NewAPIC(config.OnlineClient, dbClient)
  109. if err != nil {
  110. return &APIServer{}, err
  111. }
  112. controller.CAPIChan = apiClient.alertToPush
  113. } else {
  114. apiClient = nil
  115. controller.CAPIChan = nil
  116. }
  117. if err := controller.Init(); err != nil {
  118. return &APIServer{}, err
  119. }
  120. return &APIServer{
  121. URL: config.ListenURI,
  122. TLS: config.TLS,
  123. logFile: logFile,
  124. dbClient: dbClient,
  125. controller: controller,
  126. flushScheduler: flushScheduler,
  127. router: router,
  128. apic: apiClient,
  129. httpServerTomb: tomb.Tomb{},
  130. }, nil
  131. }
  132. func (s *APIServer) Router() (*gin.Engine, error) {
  133. return s.router, nil
  134. }
  135. func (s *APIServer) Run() error {
  136. defer types.CatchPanic("lapi/runServer")
  137. s.httpServer = &http.Server{
  138. Addr: s.URL,
  139. Handler: s.router,
  140. }
  141. if s.apic != nil {
  142. s.apic.pushTomb.Go(func() error {
  143. if err := s.apic.Push(); err != nil {
  144. log.Errorf("capi push: %s", err)
  145. return err
  146. }
  147. return nil
  148. })
  149. s.apic.pullTomb.Go(func() error {
  150. if err := s.apic.Pull(); err != nil {
  151. log.Errorf("capi pull: %s", err)
  152. return err
  153. }
  154. return nil
  155. })
  156. s.apic.metricsTomb.Go(func() error {
  157. if err := s.apic.SendMetrics(); err != nil {
  158. log.Errorf("capi metrics: %s", err)
  159. return err
  160. }
  161. return nil
  162. })
  163. }
  164. s.httpServerTomb.Go(func() error {
  165. go func() {
  166. if s.TLS != nil && s.TLS.CertFilePath != "" && s.TLS.KeyFilePath != "" {
  167. if err := s.httpServer.ListenAndServeTLS(s.TLS.CertFilePath, s.TLS.KeyFilePath); err != nil {
  168. log.Fatalf(err.Error())
  169. }
  170. } else {
  171. if err := s.httpServer.ListenAndServe(); err != http.ErrServerClosed {
  172. log.Fatalf(err.Error())
  173. }
  174. }
  175. }()
  176. <-s.httpServerTomb.Dying()
  177. log.Infof("run: shutting down api server")
  178. if err := s.Shutdown(); err != nil {
  179. log.Errorf("while shutting down API Server : %s", err)
  180. return err
  181. }
  182. return nil
  183. })
  184. return nil
  185. }
  186. func (s *APIServer) Close() {
  187. if s.apic != nil {
  188. s.apic.Shutdown() // stop apic first since it use dbClient
  189. }
  190. s.dbClient.Ent.Close()
  191. if s.flushScheduler != nil {
  192. s.flushScheduler.Stop()
  193. }
  194. }
  195. func (s *APIServer) Shutdown() error {
  196. s.Close()
  197. if err := s.httpServer.Shutdown(context.TODO()); err != nil {
  198. return err
  199. }
  200. return nil
  201. }