Example #1
0
// 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
}
Example #2
0
// 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
				}
			}
		}
	}
}