func main() { // Arguments fileName := flag.String("c", "config.json", "config file") debug := flag.Bool("d", false, "debug mode") vers := flag.Bool("v", false, "version") flag.Parse() // Version if *vers { fmt.Fprintln(os.Stdout, version.Version) os.Exit(1) } // Logging log.SetName("banshee") if *debug { log.SetLevel(log.DEBUG) } log.Debug("using %s, max %d cpu", runtime.Version(), runtime.GOMAXPROCS(-1)) // Config cfg := config.New() if flag.NFlag() == 0 || (flag.NFlag() == 1 && *debug == true) { log.Warn("no config file specified, using default..") } else { err := cfg.UpdateWithJSONFile(*fileName) if err != nil { log.Fatal("failed to load %s, %s", *fileName, err) } } // Storage options := &storage.Options{ NumGrid: cfg.Period[0], GridLen: cfg.Period[1], } db, err := storage.Open(cfg.Storage.Path, options) if err != nil { log.Fatal("failed to open %s: %v", cfg.Storage.Path, err) } // Cleaner cleaner := cleaner.New(db, cfg.Period[0]*cfg.Period[1]) go cleaner.Start() // Filter filter := filter.New() filter.Init(db) // Alerter alerter := alerter.New(cfg, db, filter) alerter.Start() // Webapp go webapp.Start(cfg, db) // Detector detector := detector.New(cfg, db, filter) detector.Out(alerter.In) detector.Start() }
// Migrate projects. // // 1. Fetch all projects from belldb. // 2. Create the project into bansheedb. // 3. Create the rules for each project. // func migrateProjects() { var projs []Project // Fetch all projects from belldb. if err := bellDB.Find(&projs).Error; err != nil { log.Fatal("fetch all projects from %s: %v", *bellDBFileName, err) } for _, proj := range projs { // Create banshee project. if err := models.ValidateProjectName(proj.Name); err != nil { log.Warn("project %s: %v, skipping..", proj.Name, err) continue } p := &models.Project{Name: proj.Name} if err := bansheeDB.Create(p).Error; err != nil { sqliteErr, ok := err.(sqlite3.Error) if ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique { log.Warn("project %s already in %s, skipping..", p.Name, *bansheeDBFileName) } else { log.Fatal("cannot create project %s: %v", p.Name, err) } } // Fetch its rules from belldb. var rules []Rule if err := bellDB.Model(proj).Related(&rules).Error; err != nil { log.Fatal("cannot fetch rules for %s: %v", p.Name, err) } for _, rule := range rules { // Create banshee rule. if err := models.ValidateRulePattern(rule.Pattern); err != nil { log.Warn("rule %s: %v, belongs to %s, skippig..", rule.Pattern, err, proj.Name) continue } r := &models.Rule{ Pattern: rule.Pattern, ProjectID: p.ID, TrendUp: rule.Up, TrendDown: rule.Down, // Important: max and min for bell is reversed with banshee's. ThresholdMax: rule.Min, ThresholdMin: rule.Max, } if err := bansheeDB.Create(r).Error; err != nil { sqliteErr, ok := err.(sqlite3.Error) if ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique { log.Warn("rule %s already in %s, skipping..", r.Pattern, *bansheeDBFileName) } else { log.Fatal("cannot create rule %s: %v", r.Pattern, err) } } } } }
// Start detector. func (d *Detector) Start() { addr := fmt.Sprintf("0.0.0.0:%d", d.cfg.Detector.Port) ln, err := net.Listen("tcp", addr) if err != nil { log.Fatal("failed to bind tcp://%s: %v", addr, err) } log.Info("detector is listening on tcp://%s..", addr) for { conn, err := ln.Accept() if err != nil { log.Fatal("accept conn: %v", err) } go d.handle(conn) } }
func initConfig() { // Config parsing. if flag.NFlag() == 0 || (flag.NFlag() == 1 && *debug) { // Case ./program [-d] log.Warn("no config specified, using default..") } else { // Update config. err := cfg.UpdateWithJSONFile(*fileName) if err != nil { log.Fatal("failed to load %s, %s", *fileName, err) } } // Config validation. err := cfg.Validate() if err != nil { log.Fatal("config: %s", err) } }
// Init. // // 1. Parse arguments. // 2. Init db handles. // 3. Auto migrate schema. // func init() { flag.Parse() // Bell DB if db, err := gorm.Open("sqlite3", *bellDBFileName); err != nil { log.Fatal("%s: %v", *bellDBFileName, err) } else { bellDB = &db bellDB.LogMode(false) } // Banshee DB if db, err := gorm.Open("sqlite3", *bansheeDBFileName); err != nil { log.Fatal("%s:%v", *bansheeDBFileName, err) } else { bansheeDB = &db bansheeDB.LogMode(false) } if err := bansheeDB.AutoMigrate(&models.Project{}, &models.Rule{}, &models.User{}).Error; err != nil { log.Fatal("failed to migrate schema for %s: %v", *bansheeDBFileName, err) } }
func initDB() { // Rely on config. if cfg == nil { panic(errors.New("db require config")) } path := cfg.Storage.Path var err error db, err = storage.Open(path) if err != nil { log.Fatal("failed to open %s: %v", path, err) } }
// Start http server. func Start(c *config.Config, d *storage.DB, f *filter.Filter) { // Init globals. cfg = c db = d flt = f // Auth auth := newAuthHandler(cfg.Webapp.Auth[0], cfg.Webapp.Auth[1]) // Routes router := httprouter.New() // Api router.GET("/api/config", auth.handler(getConfig)) router.GET("/api/interval", getInterval) router.GET("/api/privateDocUrl", getPrivateDocURL) router.GET("/api/graphiteUrl", getGraphiteURL) router.GET("/api/language", getLanguage) router.GET("/api/projects", getProjects) router.GET("/api/project/:id", getProject) router.POST("/api/project", auth.handler(createProject)) router.PATCH("/api/project/:id", auth.handler(updateProject)) router.DELETE("/api/project/:id", auth.handler(deleteProject)) router.GET("/api/project/:id/rules", auth.handler(getProjectRules)) router.GET("/api/project/:id/users", auth.handler(getProjectUsers)) router.POST("/api/project/:id/user", auth.handler(addProjectUser)) router.DELETE("/api/project/:id/user/:user_id", auth.handler(deleteProjectUser)) router.GET("/api/project/:id/events", auth.handler(getEventsByProjectID)) router.GET("/api/users", auth.handler(getUsers)) router.GET("/api/user/:id", auth.handler(getUser)) router.POST("/api/user", auth.handler(createUser)) router.DELETE("/api/user/:id", auth.handler(deleteUser)) router.PATCH("/api/user/:id", auth.handler(updateUser)) router.GET("/api/user/:id/projects", auth.handler(getUserProjects)) router.POST("/api/project/:id/rule", auth.handler(createRule)) router.DELETE("/api/rule/:id", auth.handler(deleteRule)) router.PATCH("/api/rule/:id", auth.handler(editRule)) router.GET("/api/metric/rules/:name", getMetricRules) router.GET("/api/metric/indexes", getMetricIndexes) router.GET("/api/metric/data", getMetrics) router.GET("/api/info", getInfo) router.GET("/api/version", getVersion) // Static router.NotFound = newStaticHandler(http.Dir(cfg.Webapp.Static), auth) // Serve addr := fmt.Sprintf("0.0.0.0:%d", cfg.Webapp.Port) log.Infof("webapp is listening and serving on %s..", addr) log.Fatal(http.ListenAndServe(addr, router)) }
// Start the tcp server. func (d *Detector) Start() { // Listen addr := fmt.Sprintf("0.0.0.0:%d", d.cfg.Detector.Port) ln, err := net.Listen("tcp", addr) if err != nil { log.Fatal("listen: %v", err) } log.Info("detector is listening on %s..", addr) // Accept for { conn, err := ln.Accept() if err != nil { log.Error("cannot accept conn: %v, skipping..", err) continue } go d.handle(conn) } }
// Migrate users. // // 1. Fetch all users from belldb. // 2. Create the users into bansheedb. // 3. Establish the relationships between project and user. // func migrateUsers() { var users []Receiver // Fetch all users from belldb. if err := bellDB.Find(&users).Error; err != nil { log.Fatal("fetch all users from %s: %v", *bellDBFileName, err) } for _, user := range users { // Create banshee user. err := models.ValidateUserName(user.Name) if err == nil { err = models.ValidateUserEmail(user.Email) } if err == nil { err = models.ValidateUserPhone(user.Phone) } if err != nil { log.Warn("user %s: %v, skipping..", user.Name, err) } u := &models.User{ Name: user.Name, Email: user.Email, Phone: user.Phone, EnableEmail: user.EnableEmail, EnablePhone: user.EnablePhone, Universal: user.Universal, } if err := bansheeDB.Create(u).Error; err != nil { sqliteErr, ok := err.(sqlite3.Error) if ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique { log.Warn("user %s already in %s, skipping..", u.Name, *bansheeDBFileName) } else { log.Fatal("cannot create user %s: %v", u.Name, err) } } // Establish relationship to project. if user.Universal { continue } // Get all relationships for this user. var relations []ReceiverProject if err := bellDB.Where("ReceiverId = ?", user.ID).Find(&relations).Error; err != nil { log.Fatal("cannot fetch user-project relations for user %s: %v", user.Name, err) } for _, relation := range relations { var proj Project if err := bellDB.First(&proj, relation.ProjectID).Error; err != nil { if err == gorm.RecordNotFound { log.Warn("project %d not found for user %s, skipping..", relation.ProjectID, user.Name) continue } log.Fatal("cannot get project %d for user %s", relation.ProjectID, user.Name) } p := &models.Project{} if err := bansheeDB.Where("name = ?", proj.Name).First(p).Error; err != nil { if err == gorm.RecordNotFound { log.Warn("project %s not found in %s, skipping..", proj.Name, *bansheeDBFileName) continue } log.Fatal("cannot get project %s in %s", proj.Name, *bansheeDBFileName) } if err := bansheeDB.Model(p).Association("Users").Append(u).Error; err != nil { if err == gorm.RecordNotFound { log.Warn("record not found: %v", err) continue } log.Fatal("cannot append user %s to project %s:%v", u.Name, p.Name, err) } } } }