diff --git a/api/uic.go b/api/uic.go index 87e5bab..fa9cde3 100644 --- a/api/uic.go +++ b/api/uic.go @@ -22,6 +22,10 @@ type UsersWrap struct { Users []*User `json:"users"` } +type UserMsg struct { + User *User `json:user` +} + type UsersCache struct { sync.RWMutex M map[string][]*User @@ -118,3 +122,51 @@ func CurlUic(team string) []*User { return usersWrap.Users } + +func GenSig() (string, error) { + uri := fmt.Sprintf("%s/sso/sig",g.Config().Api.Uic) + req := httplib.Get(uri).SetTimeout(2*time.Second, 10*time.Second) + sig,err := req.String() + return sig,err +} + +func LoginUrl(sig string, callback string) string { + return fmt.Sprintf("%s/auth/login?sig=%s&callback=%s",g.Config().Api.Uic,sig,callback) +} + +func UsernameFromSso( sig string ) string { + uri := fmt.Sprintf("%s/sso/user/%s?token=%s",g.Config().Api.Uic,sig,g.Config().UicToken) + req := httplib.Get(uri).SetTimeout(2*time.Second, 10*time.Second) + var userMsg UserMsg + err := req.ToJson( &userMsg ) + if err != nil { + log.Printf("curl %s fail: %v",uri,err) + return "" + } + + if strings.TrimSpace(userMsg.User.Name) == "" { + log.Printf("curl %s return none user!", uri) + return "" + } + + return userMsg.User.Name +} + +func CheckUserInTeam( username string, team string ) bool { + uri := fmt.Sprintf("%s/user/in",g.Config().Api.Uic) + req := httplib.Get(uri).SetTimeout(2*time.Second, 10*time.Second) + req.Param("name",username) + req.Param("teams",team) + checkRes,err := req.String() + + if err != nil { + log.Printf("curl %s fail: %v", uri, err) + return false + } + + if strings.TrimSpace(checkRes) == "1" { + return true + } + + return false +} diff --git a/cron/reader.go b/cron/reader.go index 0adc79b..fcbfd68 100644 --- a/cron/reader.go +++ b/cron/reader.go @@ -61,6 +61,11 @@ func popEvent(queues []string) (*model.Event, error) { return nil, err } + if g.Config().Debug { + log.Println("======>>>>redis brpoop:",params) + log.Println( reply ) + } + var event model.Event err = json.Unmarshal([]byte(reply[1]), &event) if err != nil { diff --git a/g/cfg.go b/g/cfg.go index aa15b70..8c74b7b 100644 --- a/g/cfg.go +++ b/g/cfg.go @@ -39,6 +39,7 @@ type GlobalConfig struct { Queue *QueueConfig `json:"queue"` Redis *RedisConfig `json:"redis"` Api *ApiConfig `json:"api"` + SaveFile string `json:"savefile"` } var ( diff --git a/g/eventdto.go b/g/eventdto.go index 75cbd30..aae8f9a 100644 --- a/g/eventdto.go +++ b/g/eventdto.go @@ -30,6 +30,7 @@ type EventDto struct { ExpressionId int `json:"expressionId"` StrategyId int `json:"strategyId"` TemplateId int `json:"templateId"` + ActionId int `json:"actionId"` Link string `json:"link"` } @@ -53,6 +54,12 @@ func (this OrderedEvents) Less(i, j int) bool { var Events = &SafeEvents{M: make(map[string]*EventDto)} +func (this *SafeEvents) Init(m map[string]*EventDto) { + this.Lock() + defer this.Unlock() + this.M = m +} + func (this *SafeEvents) Delete(id string) { this.Lock() defer this.Unlock() @@ -102,6 +109,7 @@ func (this *SafeEvents) Put(event *model.Event) { dto.ExpressionId = event.ExpressionId() dto.StrategyId = event.StrategyId() dto.TemplateId = event.TplId() + dto.ActionId = event.ActionId() dto.Link = Link(event) diff --git a/g/savetofile.go b/g/savetofile.go new file mode 100644 index 0000000..eeeb520 --- /dev/null +++ b/g/savetofile.go @@ -0,0 +1,51 @@ +package g + +import( + "os" + "io/ioutil" + "encoding/json" + "log" +) + + +func SaveCacheToFile() { + event := Events.Clone() + body, err := json.Marshal(event) + if err != nil { + log.Println("SaveCacheToFile Fail:",err) + return + } + + if config.SaveFile == "" { + log.Println("config savefile is empty") + return + } + err2 := ioutil.WriteFile(config.SaveFile, body, 0666) + if err2 != nil { + log.Println("SaveCacheToFile save event list to file Fail!",err2) + } +} + +func ReadCacheFromFile() { + fi,err := os.Open( config.SaveFile ) + if err != nil { + log.Println("ReadCacheFromFile , cache file open fail:",err) + return + } + + defer fi.Close() + + var events map[string]*EventDto + fd,err := ioutil.ReadAll(fi) + jerr := json.Unmarshal(fd,&events) + if err != nil || jerr != nil { + log.Println("ReadCacheFromFile, json decode cache file content error: ", err,jerr) + return + } + + if config.Debug { + log.Println("read event from cache file is:",string(fd)) + } + + Events.Init(events) +} diff --git a/http/controller.go b/http/controller.go index 2af4d42..b056f6d 100644 --- a/http/controller.go +++ b/http/controller.go @@ -4,9 +4,11 @@ import ( "fmt" "github.com/astaxie/beego" "github.com/open-falcon/alarm/g" + "github.com/open-falcon/alarm/api" "github.com/toolkits/file" "sort" "strings" + "log" "time" ) @@ -22,16 +24,21 @@ func (this *MainController) Health() { this.Ctx.WriteString("ok") } +func (this *MainController) EventList() { + events := g.Events.Clone() + this.Ctx.Output.JSON(events,false,false) +} + func (this *MainController) Workdir() { this.Ctx.WriteString(fmt.Sprintf("%s", file.SelfDir())) } func (this *MainController) ConfigReload() { - remoteAddr := this.Ctx.Input.Request.RemoteAddr + remoteAddr := this.Ctx.Request.RemoteAddr if strings.HasPrefix(remoteAddr, "127.0.0.1") { g.ParseConfig(g.ConfigFile) this.Data["json"] = g.Config() - this.ServeJson() + this.ServeJSON() } else { this.Ctx.WriteString("no privilege") } @@ -42,9 +49,12 @@ func (this *MainController) Index() { defer func() { this.Data["Now"] = time.Now().Unix() - this.TplNames = "index.html" + this.TplName = "index.html" }() + username := getLoginUser( this ) + this.Data["username"] = username + if len(events) == 0 { this.Data["Events"] = []*g.EventDto{} return @@ -57,11 +67,13 @@ func (this *MainController) Index() { } // 按照持续时间排序 - beforeOrder := make([]*g.EventDto, count) - i := 0 + beforeOrder := make([]*g.EventDto, 0) + + //筛选event,只有属于同一用户team的才可被展示 for _, event := range events { - beforeOrder[i] = event - i++ + if checkEventBelongUser( event, username ) { + beforeOrder = append(beforeOrder,event) + } } sort.Sort(g.OrderedEvents(beforeOrder)) @@ -82,3 +94,39 @@ func (this *MainController) Solve() { this.Ctx.WriteString("") } + +func getLoginUser( this *MainController ) string { + sig := this.Ctx.GetCookie("sig") + if strings.TrimSpace( sig ) == "" { + redirectToSso( this ) + } + + username := api.UsernameFromSso( sig ) + if username == "" { + redirectToSso( this ) + } + + return username +} + +func redirectToSso( this *MainController ) { + sig,err := api.GenSig() + if err != nil { + log.Println("get sig from uic fail", err) + return + } + this.Ctx.SetCookie("sig",sig) + loginurl := api.LoginUrl(sig,this.Ctx.Input.Scheme()+"://"+this.Ctx.Request.Host+this.Ctx.Request.RequestURI) + this.Ctx.Redirect(302,loginurl) +} + +func checkEventBelongUser( e *g.EventDto, username string) bool { + //get event action id + actionId := e.ActionId + + //获取event对应的uic team + uicTeam := api.GetAction(actionId).Uic + + //当前登录user是否为此team成员 + return api.CheckUserInTeam(username,uicTeam) +} diff --git a/http/http.go b/http/http.go index 1e67dc3..98d126c 100644 --- a/http/http.go +++ b/http/http.go @@ -14,6 +14,7 @@ func configRoutes() { beego.Router("/health", &MainController{}, "get:Health") beego.Router("/workdir", &MainController{}, "get:Workdir") beego.Router("/config/reload", &MainController{}, "get:ConfigReload") + beego.Router("/eventlist", &MainController{}, "get:EventList") beego.Router("/event/solve", &MainController{}, "post:Solve") } @@ -62,9 +63,9 @@ func Start() { } if g.Config().Debug { - beego.RunMode = "dev" + beego.BConfig.RunMode = "dev" } else { - beego.RunMode = "prod" + beego.BConfig.RunMode = "prod" } beego.Run(addr) diff --git a/main.go b/main.go index 5becef4..53b1104 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,8 @@ func main() { g.ParseConfig(*cfg) g.InitRedisConnPool() + //初始化,从cache文件中获取event list + g.ReadCacheFromFile() go http.Start() @@ -38,10 +40,12 @@ func main() { go cron.CombineMail() sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) go func() { <-sigs fmt.Println() + //将当前的未恢复报警落地到文件 + g.SaveCacheToFile() g.RedisConnPool.Close() os.Exit(0) }() diff --git a/views/index.html b/views/index.html index 71def05..8343af0 100644 --- a/views/index.html +++ b/views/index.html @@ -15,6 +15,10 @@
+ +