// processOlderMessages processes older messages that have been persisted in various locations (like from pending & current folders) func (p *Processor) processOlderMessages() { log := p.context.Log() instanceID, err := platform.InstanceID() if err != nil { log.Errorf("error fetching instance id, %v", err) return } //process older messages from PENDING folder unprocessedMsgsLocation := path.Join(appconfig.DefaultDataStorePath, instanceID, appconfig.DefaultCommandRootDirName, appconfig.DefaultLocationOfState, appconfig.DefaultLocationOfPending) if isDirectoryEmpty, _ := fileutil.IsDirEmpty(unprocessedMsgsLocation); isDirectoryEmpty { log.Debugf("No messages to process from %v", unprocessedMsgsLocation) } else { //get all pending messages files, err := ioutil.ReadDir(unprocessedMsgsLocation) //TODO: revisit this when bookkeeping is made invasive if err != nil { log.Errorf("skipping reading pending messages from %v. unexpected error encountered - %v", unprocessedMsgsLocation, err) return } //iterate through all pending messages for _, f := range files { log.Debugf("Processing an older message with messageID - %v", f.Name()) //construct the absolute path - safely assuming that interim state for older messages are already present in Pending folder file := path.Join(appconfig.DefaultDataStorePath, instanceID, appconfig.DefaultCommandRootDirName, appconfig.DefaultLocationOfState, appconfig.DefaultLocationOfPending, f.Name()) var msg ssmmds.Message //parse the message if err := jsonutil.UnmarshalFile(file, &msg); err != nil { log.Errorf("skipping processsing of pending messages. encountered error %v while reading pending message from file - %v", err, f) } else { //call processMessage for every message read from the pending folder //we will end up sending acks again for this message - but that's ok because //unless a message has been deleted - multiple acks are allowed by MDS. //If this becomes an issue - we can stub out ack part from processMessage p.processMessage(&msg) } } } //process older messages from CURRENT folder p.processMessagesFromCurrent(instanceID) return }
// processOlderMessagesFromCurrent processes older messages that were persisted in CURRENT folder func (p *Processor) processMessagesFromCurrent(instanceID string) { log := p.context.Log() config := p.context.AppConfig() unprocessedMsgsLocation := path.Join(appconfig.DefaultDataStorePath, instanceID, appconfig.DefaultCommandRootDirName, appconfig.DefaultLocationOfState, appconfig.DefaultLocationOfCurrent) if isDirectoryEmpty, _ := fileutil.IsDirEmpty(unprocessedMsgsLocation); isDirectoryEmpty { log.Debugf("no older messages to process from %v", unprocessedMsgsLocation) } else { //get all older messages from previous run of agent files, err := ioutil.ReadDir(unprocessedMsgsLocation) //TODO: revisit this when bookkeeping is made invasive if err != nil { log.Errorf("skipping reading inprogress messages from %v. unexpected error encountered - %v", unprocessedMsgsLocation, err) return } //iterate through all old executing messages for _, f := range files { log.Debugf("processing previously unexecuted message - %v", f.Name()) //construct the absolute path - safely assuming that interim state for older messages are already present in Current folder file := path.Join(appconfig.DefaultDataStorePath, instanceID, appconfig.DefaultCommandRootDirName, appconfig.DefaultLocationOfState, appconfig.DefaultLocationOfCurrent, f.Name()) var oldCmdState messageContracts.CommandState //parse the message //TODO: Not all messages in Current folder correspond to SendCommand. if err := jsonutil.UnmarshalFile(file, &oldCmdState); err != nil { log.Errorf("skipping processsing of previously unexecuted messages. encountered error %v while reading unprocessed message from file - %v", err, f) } else { if oldCmdState.DocumentInformation.RunCount >= config.Mds.CommandRetryLimit { //TODO: Move command to corrupt/failed // do not process as the command has failed too many times break } pluginOutputs := make(map[string]*contracts.PluginResult) // increment the command run count oldCmdState.DocumentInformation.RunCount++ // Update reboot status for v := range oldCmdState.PluginsInformation { plugin := oldCmdState.PluginsInformation[v] if plugin.HasExecuted && plugin.Result.Status == contracts.ResultStatusSuccessAndReboot { log.Debugf("plugin %v has completed a reboot. Setting status to Success.", v) plugin.Result.Status = contracts.ResultStatusSuccess oldCmdState.PluginsInformation[v] = plugin pluginOutputs[v] = &plugin.Result p.sendResponse(oldCmdState.DocumentInformation.MessageID, v, pluginOutputs) } } // func PersistData(log log.T, commandID, instanceID, locationFolder string, object interface{}) { commandStateHelper.PersistData(log, oldCmdState.DocumentInformation.CommandID, instanceID, appconfig.DefaultLocationOfCurrent, oldCmdState) //Submit the work to Job Pool so that we don't block for processing of new messages err := p.sendCommandPool.Submit(log, oldCmdState.DocumentInformation.MessageID, func(cancelFlag task.CancelFlag) { p.runCmdsUsingCmdState(p.context.With("[messageID="+oldCmdState.DocumentInformation.MessageID+"]"), p.service, p.pluginRunner, cancelFlag, p.buildReply, p.sendResponse, oldCmdState) }) if err != nil { log.Error("SendCommand failed for previously unexecuted commands", err) return } } } } }