func main() { logging.InitializeLogging() // user needs help var needHelp bool // configuration file var configFile string // set up flag to point at conf, parse arguments and then verify flag.BoolVar(&needHelp, "help", false, "display this dialog") flag.StringVar(&configFile, "config", "", "JSON configuration file") flag.Parse() if needHelp { flag.Usage() os.Exit(1) } // defult configuration viper.SetDefault("username", "project8") viper.SetDefault("log-level", "INFO") // load config viper.SetConfigFile(configFile) if parseErr := viper.ReadInConfig(); parseErr != nil { logging.Log.Criticalf("%v", parseErr) os.Exit(1) } logging.Log.Notice("Config file loaded") logging.ConfigureLogging(viper.GetString("log-level")) logging.Log.Infof("Log level: %v", viper.GetString("log-level")) userName := viper.GetString("username") if !viper.IsSet("channels") { logging.Log.Critical("No channel configuration found") os.Exit(1) } // check authentication for desired username if authErr := authentication.Load(); authErr != nil { logging.Log.Criticalf("Error in loading authenticators: %v", authErr) os.Exit(1) } if !authentication.SlackAvailable(userName) { logging.Log.Criticalf("Authentication for user <%s> is not available", userName) os.Exit(1) } authToken := authentication.SlackToken(userName) logging.Log.Infof("Slack username: %s", userName) logging.Log.Infof("Slack token: %s", authToken) // get the slack API object api := slack.New(authToken) if api == nil { logging.Log.Critical("Unable to make a new Slack API") os.Exit(1) } logging.Log.Info("Created Slack API") // get list of users and then the user ID userID := "" users, usersErr := api.GetUsers() if usersErr != nil { logging.Log.Criticalf("Unable to get users: %s", usersErr) os.Exit(1) } else { usernameLoop: for _, user := range users { if user.Name == userName { userID = user.ID break usernameLoop } } } if userID == "" { logging.Log.Criticalf("Could not get user ID for user <%s>", userName) os.Exit(1) } logging.Log.Infof("User ID: %s", userID) // get map of channel IDs var allChannelMap map[string]string channels, chanErr := api.GetChannels(true) if chanErr != nil { logging.Log.Criticalf("Unable to get channels: %s", chanErr) os.Exit(1) } else { allChannelMap = make(map[string]string, len(channels)) for _, aChan := range channels { allChannelMap[aChan.Name] = aChan.ID logging.Log.Debugf("Channel %s has ID %s", aChan.Name, aChan.ID) } } var threadWait sync.WaitGroup recipientChan := make(chan eventRecipient, 10) // loop over channels channelsRaw := viper.GetStringMap("channels") for channelName, _ := range channelsRaw { // get channel ID if channelID, channelExists := allChannelMap[channelName]; channelExists == true { logging.Log.Infof("(%s) Found request for channel %s", channelID, channelName) //channelInfo := channelInfoRaw.(map[string](interface{})) channelConfigName := "channels." + channelName sizeLimitCN := channelConfigName + ".size-limit" sizeLimit := -1 monitorSize := false // size will not be monitored if size-limit is not set in the configuration if viper.IsSet(sizeLimitCN) { sizeLimit = viper.GetInt(sizeLimitCN) monitorSize = viper.GetBool(channelConfigName + ".monitor-size") } if sizeLimit < 0 { logging.Log.Errorf("(%s) Invalid size limit", channelID) continue } doLogging := false // future feature msgQueue := utility.NewQueue() var buildHistLock sync.Mutex histCond := sync.NewCond(&buildHistLock) if monitorSize || doLogging { if !monitorStarted { logging.Log.Notice("Launching monitorSlack") threadWait.Add(1) go monitorSlack(api, &threadWait, recipientChan) monitorStarted = true } recipient := eventRecipient{ channelID: channelID, eventChan: make(chan *slack.MessageEvent, 100), } recipientChan <- recipient logging.Log.Noticef("(%s) Launching monitorChannel", channelID) threadWait.Add(1) go monitorChannel(channelID, api, recipient.eventChan, msgQueue, monitorSize, doLogging, histCond, &threadWait) // If we're monitoring the channel, then we increase the size limit for cleanHistory by 1. // This is because the latest message will be passed to the monitor as the first message received. // So the monitor will then remove an old message; so we leave one extra old message to be removed // once the monitoring begins. sizeLimit++ } logging.Log.Noticef("(%s) Launching cleanHistory", channelID) threadWait.Add(1) go cleanHistory(channelID, api, msgQueue, sizeLimit, histCond, &threadWait) } else { logging.Log.Warningf("Channel <%s> does not exist", channelName) } } logging.Log.Notice("Waiting for threads to finish") threadWait.Wait() logging.Log.Notice("Threads complete") return }
func main() { logging.InitializeLogging() // user needs help var needHelp bool // configuration file var configFile string // set up flag to point at conf, parse arguments and then verify flag.BoolVar(&needHelp, "help", false, "Display this dialog") flag.StringVar(&configFile, "config", "", "JSON configuration file") flag.Parse() if needHelp { flag.Usage() os.Exit(1) } // defult configuration viper.SetDefault("log-level", "INFO") viper.SetDefault("broker", "localhost") viper.SetDefault("queue", "mdreceiver") // load config if configFile != "" { viper.SetConfigFile(configFile) if parseErr := viper.ReadInConfig(); parseErr != nil { logging.Log.Criticalf("%v", parseErr) os.Exit(1) } logging.Log.Notice("Config file loaded") } logging.ConfigureLogging(viper.GetString("log-level")) logging.Log.Infof("Log level: %v", viper.GetString("log-level")) broker := viper.GetString("broker") queueName := viper.GetString("queue") // check authentication for desired username if authErr := authentication.Load(); authErr != nil { logging.Log.Criticalf("Error in loading authenticators: %v", authErr) os.Exit(1) } if !authentication.AmqpAvailable() { logging.Log.Critical("Authentication for AMQP is not available") os.Exit(1) } amqpUser := authentication.AmqpUsername() amqpPassword := authentication.AmqpPassword() url := "amqp://" + amqpUser + ":" + amqpPassword + "@" + broker service := dripline.StartService(url, queueName) if service == nil { logging.Log.Critical("AMQP service did not start") os.Exit(1) } logging.Log.Info("AMQP service started") // add .# to the queue name for the subscription subscriptionKey := queueName + ".#" if subscribeErr := service.SubscribeToRequests(subscriptionKey); subscribeErr != nil { logging.Log.Criticalf("Could not subscribe to requests at <%v>: %v", subscriptionKey, subscribeErr) os.Exit(1) } if msiErr := fillMasterSenderInfo(); msiErr != nil { logging.Log.Criticalf("Could not fill out master sender info: %v", MasterSenderInfo) os.Exit(1) } //context := build.defaultContext() //os.Exit(2) receiverLoop: for { select { case request, chanOpen := <-service.Receiver.RequestChan: if !chanOpen { logging.Log.Error("Incoming request channel is closed") break receiverLoop } logging.Log.Debug("Received request") switch request.MsgOp { case dripline.MOCommand: var instruction string if request.Message.Target != queueName { instruction = strings.TrimPrefix(request.Message.Target, queueName+".") } logging.Log.Debugf("Command instruction: %s", instruction) switch instruction { case "write_json": logging.Log.Debug("Received \"write_json\" instruction") //logging.Log.Warningf("type: %v", reflect.TypeOf(request.Message.Payload)) //logging.Log.Warningf("try printing the payload? \n%v", request.Message.Payload) payloadAsMap, okPAM := request.Message.Payload.(map[interface{}]interface{}) if !okPAM { if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripPayload, "Unable to convert payload to map; aborting message", MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } filenameIfc, hasFN := payloadAsMap["filename"] if !hasFN { if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripPayload, "No filename present in message; aborting", MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } thePath, okFP := utility.TryConvertToString(filenameIfc) if okFP != nil { if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripPayload, "Unable to convert filename to string; aborting message", MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } logging.Log.Debugf("Filename to write: %s", thePath) dir, _ := filepath.Split(thePath) // check whether the directory exists _, dirStatErr := os.Stat(dir) if dirStatErr != nil && os.IsNotExist(dirStatErr) { if mkdirErr := os.MkdirAll(dir, os.ModeDir|0775); mkdirErr != nil { msgText := fmt.Sprintf("Unable to create the directory <%q>", dir) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrHW, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } // Add a small delay after creating the new directory so that anything (e.g. Hornet) waiting for that directory can react to it before the JSON file is created time.Sleep(100 * time.Millisecond) } contentsIfc, hasContents := payloadAsMap["contents"] if !hasContents { msgText := fmt.Sprintf("No file contents present in the message for <%q>", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripPayload, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } encoded, jsonErr := utility.IfcToJSON(&contentsIfc) if jsonErr != nil { msgText := fmt.Sprintf("Unable to convert file contents to JSON for <%q>", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripPayload, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } theFile, fileErr := os.Create(thePath) if fileErr != nil { msgText := fmt.Sprintf("Unable to create the file <%q>", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrHW, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } _, writeErr := theFile.Write(encoded) if writeErr != nil { theFile.Close() msgText := fmt.Sprintf("Unable to write to the file <%q>", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrHW, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } closeErr := theFile.Close() if closeErr != nil { msgText := fmt.Sprintf("Unable to close the file <%q>", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrHW, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } msgText := fmt.Sprintf("File written: %q", thePath) if sendErr := PrepareAndSendReply(service, request, dripline.RCSuccess, msgText, MasterSenderInfo); sendErr != nil { break receiverLoop } default: message := "Incoming request operation instruction not handled: " + instruction if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripMethod, message, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } default: message := "Incoming request operation type not handled: " + strconv.FormatUint(uint64(request.MsgOp), 10) if sendErr := PrepareAndSendReply(service, request, dripline.RCErrDripMethod, message, MasterSenderInfo); sendErr != nil { break receiverLoop } continue receiverLoop } } } logging.Log.Info("MdReceiver is finished") }
func main() { logging.InitializeLogging() // user needs help var needHelp bool // configuration file var configFile string // set up flag to point at conf, parse arguments and then verify flag.BoolVar(&needHelp, "help", false, "Display this dialog") flag.StringVar(&configFile, "config", "", "JSON configuration file") flag.Parse() if needHelp { flag.Usage() os.Exit(1) } // defult configuration viper.SetDefault("log-level", "INFO") viper.SetDefault("broker", "localhost") viper.SetDefault("wait-interval", "1m") viper.SetDefault("subscribe-queue", "diopsid-queue") viper.SetDefault("alerts-queue", "disk_status.machinename") // load config if configFile != "" { viper.SetConfigFile(configFile) if parseErr := viper.ReadInConfig(); parseErr != nil { logging.Log.Criticalf("%v", parseErr) os.Exit(1) } logging.Log.Notice("Config file loaded") } logging.ConfigureLogging(viper.GetString("log-level")) logging.Log.Infof("Log level: %v", viper.GetString("log-level")) wheretolook := viper.GetStringSlice("where-to-look") if len(wheretolook) == 0 { logging.Log.Critical("No directories were provided") os.Exit(1) } // computername := viper.GetString("computer-name") // computername,e := os.Hostname() // if e != nil { // logging.Log.Criticalf("Couldn't get the hostname") // return // } broker := viper.GetString("broker") queueName := viper.GetString("subscribe-queue") alertsQueueName := viper.GetString("alerts-queue") waitInterval := viper.GetDuration("wait-interval") // check authentication for desired username if authErr := authentication.Load(); authErr != nil { logging.Log.Criticalf("Error in loading authenticators: %v", authErr) os.Exit(1) } if !authentication.AmqpAvailable() { logging.Log.Critical("Authentication for AMQP is not available") os.Exit(1) } amqpUser := authentication.AmqpUsername() amqpPassword := authentication.AmqpPassword() url := "amqp://" + amqpUser + ":" + amqpPassword + "@" + broker service := dripline.StartService(url, queueName) if service == nil { logging.Log.Critical("AMQP service did not start") os.Exit(1) } logging.Log.Info("AMQP service started") // add .# to the queue name for the subscription // the queue name does not have to be the same as the queue where to send the alerts! // it is better to define a proper queueName in the config file to prevent // conflict between services subscribing to the same queue (which is not allowed!) subscriptionKey := queueName + ".#" if subscribeErr := service.SubscribeToAlerts(subscriptionKey); subscribeErr != nil { logging.Log.Criticalf("Could not subscribe to alerts at <%v>: %v", subscriptionKey, subscribeErr) os.Exit(1) } if msiErr := fillMasterSenderInfo(); msiErr != nil { logging.Log.Criticalf("Could not fill out master sender info: %v", MasterSenderInfo) os.Exit(1) } for { for _, dir := range wheretolook { alert := dripline.PrepareAlert(alertsQueueName, "application/json", MasterSenderInfo) disk := DiskUsage(dir) var payload map[string]interface{} payload = make(map[string]interface{}) payload["directory"] = dir payload["all"] = float64(disk.All) / float64(GB) payload["used"] = float64(disk.Used) / float64(GB) alert.Message.Payload = payload e := service.SendAlert(alert) logging.Log.Infof("Alert sent: [%s] All: %.2f GB Used: %.2f GB", dir, float64(disk.All)/float64(GB), float64(disk.Used)/float64(GB)) if e != nil { logging.Log.Errorf("Could not send the alert: %v", e) } } logging.Log.Infof("Sleeping now") time.Sleep(waitInterval) } }