//Sync Watch Process func startSyncWatchProcess(server *Server) { config := util.GetConfig() watch := config.GetStringList("watch/keys", nil) events := config.GetStringList("watch/events", nil) if watch == nil { return } extensions := map[string]extension.Environment{} for _, event := range events { path := "sync://" + event env, err := server.NewEnvironmentForPath("sync."+event, path) if err != nil { log.Fatal(err.Error()) } extensions[event] = env } responseChan := make(chan *gohan_sync.Event) stopChan := make(chan bool) for _, path := range watch { go func(path string) { defer util.LogFatalPanic(log) for server.running { lockKey := lockPath + "watch" err := server.sync.Lock(lockKey, true) if err != nil { log.Warning("Can't start watch process due to lock", err) time.Sleep(5 * time.Second) continue } defer func() { server.sync.Unlock(lockKey) }() err = server.sync.Watch(path, responseChan, stopChan) if err != nil { log.Error(fmt.Sprintf("sync watch error: %s", err)) } } }(path) } //main response lisnter process go func() { defer util.LogFatalPanic(log) for server.running { response := <-responseChan server.queue.Add(job.NewJob( func() { defer util.LogPanic(log) for _, event := range events { //match extensions if strings.HasPrefix(response.Key, "/"+event) { env := extensions[event] runExtensionOnSync(server, response, env.Clone()) return } } })) } }() }
//SNMP Process //Experimental func startSNMPProcess(server *Server) { config := util.GetConfig() enabled := config.GetParam("snmp", nil) if enabled == nil { return } host := config.GetString("snmp/address", "localhost:162") path := "snmp://" env, err := server.NewEnvironmentForPath("snmp", path) if err != nil { log.Fatal(err.Error()) } addr, err := net.ResolveUDPAddr("udp", host) if err != nil { log.Fatal(err) } conn, err := net.ListenUDP("udp", addr) if err != nil { log.Fatal(err) } buf := make([]byte, 1024) go func() { defer util.LogFatalPanic(log) defer conn.Close() for server.running { rlen, remote, err := conn.ReadFromUDP(buf) if err != nil { log.Error(fmt.Sprintf("[SNMP] failed read bytes %s", err)) return } decoded, err := wapsnmp.DecodeSequence(buf[:rlen]) if err != nil { log.Error(fmt.Sprintf("[SNMP] failed decode bytes %s", err)) continue } infos := decoded[3].([]interface{})[4].([]interface{})[1:] trap := map[string]string{} for _, info := range infos { listInfo := info.([]interface{}) oid := listInfo[1].(wapsnmp.Oid) trap[oid.String()] = fmt.Sprintf("%v", listInfo[2]) } context := map[string]interface{}{ "trap": trap, "remote": remote, } if err := env.HandleEvent("notification", context); err != nil { log.Warning(fmt.Sprintf("extension error: %s", err)) } } }() }
//CRON Process func startCRONProcess(server *Server) { config := util.GetConfig() jobList := config.GetParam("cron", nil) if jobList == nil { return } if server.sync == nil { log.Fatalf(fmt.Sprintf("Could not start CRON process because of sync backend misconfiguration.")) util.LogFatalPanic(log) } log.Info("Started CRON process") c := cron.New() for _, rawJob := range jobList.([]interface{}) { job := rawJob.(map[string]interface{}) path := job["path"].(string) timing := job["timing"].(string) name := strings.TrimPrefix(path, "cron://") env, err := server.NewEnvironmentForPath(name, path) if err != nil { log.Fatal(err.Error()) } log.Info("New job for %s / %s", path, timing) c.AddFunc(timing, func() { lockKey := lockPath + "/" + path err := server.sync.Lock(lockKey, false) if err != nil { return } defer func() { server.sync.Unlock(lockKey) }() context := map[string]interface{}{ "path": path, } if err != nil { log.Warning(fmt.Sprintf("extension error: %s", err)) return } if err := env.HandleEvent("notification", context); err != nil { log.Warning(fmt.Sprintf("extension error: %s", err)) return } return }) } c.Start() }
//Start sync Process func startSyncProcess(server *Server) { pollingTicker := time.Tick(eventPollingTime) committed := transactionCommitInformer() go func() { defer util.LogFatalPanic(log) recentlySynced := false for server.running { select { case <-pollingTicker: if recentlySynced { recentlySynced = false continue } case <-committed: recentlySynced = true } server.sync.Lock(syncPath, true) server.Sync() } server.sync.Unlock(syncPath) }() }
//TODO(nati) integrate with watch process func startStateUpdatingProcess(server *Server) { stateResponseChan := make(chan *gohan_sync.Event) stateStopChan := make(chan bool) if _, err := server.sync.Fetch(statePrefix); err != nil { server.sync.Update(statePrefix, "") } if _, err := server.sync.Fetch(monitoringPrefix); err != nil { server.sync.Update(monitoringPrefix, "") } go func() { defer util.LogFatalPanic(log) for server.running { lockKey := lockPath + "state" err := server.sync.Lock(lockKey, true) if err != nil { log.Warning("Can't start state watch process due to lock", err) time.Sleep(5 * time.Second) continue } defer func() { server.sync.Unlock(lockKey) }() err = server.sync.Watch(statePrefix, stateResponseChan, stateStopChan) if err != nil { log.Error(fmt.Sprintf("sync watch error: %s", err)) } } }() go func() { defer util.LogFatalPanic(log) for server.running { response := <-stateResponseChan err := StateUpdate(response, server) if err != nil { log.Warning(fmt.Sprintf("error during state update: %s", err)) } } stateStopChan <- true }() monitoringResponseChan := make(chan *gohan_sync.Event) monitoringStopChan := make(chan bool) go func() { defer util.LogFatalPanic(log) for server.running { lockKey := lockPath + "monitoring" err := server.sync.Lock(lockKey, true) if err != nil { log.Warning("Can't start state watch process due to lock", err) time.Sleep(5 * time.Second) continue } defer func() { server.sync.Unlock(lockKey) }() err = server.sync.Watch(monitoringPrefix, monitoringResponseChan, monitoringStopChan) if err != nil { log.Error(fmt.Sprintf("sync watch error: %s", err)) } } }() go func() { defer util.LogFatalPanic(log) for server.running { response := <-monitoringResponseChan err := MonitoringUpdate(response, server) if err != nil { log.Warning(fmt.Sprintf("error during state update: %s", err)) } } monitoringStopChan <- true }() }
//TODO(nati) integrate with watch process func startStateWatchProcess(server *Server) { stateResponseChan := make(chan *gohan_sync.Event) stateStopChan := make(chan bool) for _, toCreate := range []string{stateWatchPrefix, statePrefix, monitoringPrefix} { if _, err := server.sync.Fetch(toCreate); err != nil { server.sync.Update(toCreate, "") } } go func() { defer util.LogFatalPanic(log) for server.running { lockKey := lockPath + "/state_watch" err := server.sync.Lock(lockKey, true) if err != nil { log.Warning("Can't start state watch process due to lock", err) time.Sleep(5 * time.Second) continue } defer func() { server.sync.Unlock(lockKey) }() err = server.sync.Watch(stateWatchPrefix, stateResponseChan, stateStopChan) if err != nil { log.Error(fmt.Sprintf("sync state watch error: %s", err)) } } }() go func() { defer util.LogFatalPanic(log) var bufferMutex sync.Mutex buffers := make(map[string]chan *gohan_sync.Event) for server.running { response := <-stateResponseChan key := stateWatchTrimmer.ReplaceAllLiteralString(response.Key, "") bufferMutex.Lock() buffer, ok := buffers[key] if !ok { buffer = make(chan *gohan_sync.Event, bufferSize) buffers[key] = buffer go func(buf chan *gohan_sync.Event, key string) { for { var resp *gohan_sync.Event bufferMutex.Lock() select { case resp = <-buf: bufferMutex.Unlock() default: close(buf) delete(buffers, key) bufferMutex.Unlock() return } var err error if strings.HasPrefix(resp.Key, statePrefix) { err = StateUpdate(resp, server) log.Info("Completed StateUpdate") } else if strings.HasPrefix(resp.Key, monitoringPrefix) { err = MonitoringUpdate(resp, server) log.Info("Completed MonitoringUpdate") } if err != nil { log.Warning(fmt.Sprintf("error during state update: %s", err)) } } }(buffer, key) } buffer <- response bufferMutex.Unlock() } stateStopChan <- true }() }
func listenAMQP(server *Server) { hostname, _ := os.Hostname() processID := hostname + uuid.NewV4().String() config := util.GetConfig() connection := config.GetString("amqp/connection", "amqp://*****:*****@127.0.0.1:5672/") queues := config.GetStringList("amqp/queues", []string{"notifications.info", "notifications.error"}) events := config.GetStringList("amqp/events", []string{}) extensions := map[string]extension.Environment{} for _, event := range events { path := "amqp://" + event env, err := server.NewEnvironmentForPath("amqp."+event, path) if err != nil { log.Fatal(err.Error()) } extensions[event] = env } for _, queue := range queues { go func(queue string) { defer util.LogFatalPanic(log) for server.running { conn, err := amqp.Dial(connection) if err != nil { log.Error(fmt.Sprintf("[AMQP] connection error: %s", err)) time.Sleep(connectionWait) continue } defer conn.Close() ch, err := conn.Channel() if err != nil { log.Error(fmt.Sprintf("[AMQP] channel: %s", err)) return } defer ch.Close() q, err := ch.QueueDeclare( queue, // name false, // durable false, // delete when usused false, // exclusive false, // no-wait nil, // arguments ) if err != nil { log.Error(fmt.Sprintf("[AMQP] queue declare error: %s", err)) return } for server.running { msgs, err := ch.Consume( q.Name, // queue "gohan-"+processID+"-"+queue, // consumer true, // auto-ack false, // exclusive false, // no-local false, // no-wait nil, // args ) if err != nil { log.Error(fmt.Sprintf("[AMQP] consume queue error: %s", err)) break } for d := range msgs { var message map[string]interface{} err = json.Unmarshal(d.Body, &message) log.Debug(fmt.Sprintf("Received a message: %s %s", queue, d.Body)) if err != nil { log.Error(fmt.Sprintf("[AMQP] json decode error: %s", err)) continue } eventType, ok := message["event_type"].(string) if !ok { log.Error("[AMQP] wrong event type") continue } for _, event := range events { if strings.HasPrefix(eventType, event) { env := extensions[event] context := map[string]interface{}{ "event": message, } if err := env.HandleEvent("notification", context); err != nil { log.Warning(fmt.Sprintf("extension error: %s", err)) } } } } } } }(queue) } }