// Execute runs multiple sets of commands and returns their outputs. // res.Output will contain a slice of RunCommandPluginOutput. func (p *Plugin) Execute(context context.T, config contracts.Configuration, cancelFlag task.CancelFlag) (res contracts.PluginResult) { log := context.Log() log.Info("RunCommand started with configuration ", config) util := new(updateutil.Utility) manager := new(updateManager) res.StartDateTime = time.Now() defer func() { res.EndDateTime = time.Now() }() //loading Properties as list since aws:updateSsmAgent uses properties as list var properties []interface{} if properties, res = pluginutil.LoadParametersAsList(log, config.Properties); res.Code != 0 { return res } out := make([]UpdatePluginOutput, len(properties)) for i, prop := range properties { // check if a reboot has been requested if rebooter.RebootRequested() { log.Info("A plugin has requested a reboot.") break } if cancelFlag.ShutDown() { out[i] = UpdatePluginOutput{} out[i].Errors = []string{"Execution canceled due to ShutDown"} break } else if cancelFlag.Canceled() { out[i] = UpdatePluginOutput{} out[i].Errors = []string{"Execution canceled"} break } out[i] = updateAgent(p, config, log, manager, util, prop, cancelFlag, config.OutputS3BucketName, config.OutputS3KeyPrefix, res.StartDateTime) res.Code = out[i].ExitCode res.Status = out[i].Status res.Output = fmt.Sprintf("%v", out[i].String()) } return }
// Execute runs multiple sets of commands and returns their outputs. // res.Output will contain a slice of RunCommandPluginOutput. func (p *Plugin) Execute(context context.T, config contracts.Configuration, cancelFlag task.CancelFlag) (res contracts.PluginResult) { log := context.Log() log.Infof("%v started with configuration %v", Name(), config) res.StartDateTime = time.Now() defer func() { res.EndDateTime = time.Now() }() //loading Properties as list since aws:runPowershellScript & aws:runShellScript uses properties as list var properties []interface{} if properties, res = pluginutil.LoadParametersAsList(log, config.Properties); res.Code != 0 { pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return res } out := make([]contracts.PluginOutput, len(properties)) for i, prop := range properties { // check if a reboot has been requested if rebooter.RebootRequested() { log.Info("A plugin has requested a reboot.") return } if cancelFlag.ShutDown() { out[i] = contracts.PluginOutput{Errors: []string{"Execution canceled due to ShutDown"}} out[i].ExitCode = 1 out[i].Status = contracts.ResultStatusFailed break } if cancelFlag.Canceled() { out[i] = contracts.PluginOutput{Errors: []string{"Execution canceled"}} out[i].ExitCode = 1 out[i].Status = contracts.ResultStatusCancelled break } out[i] = p.runCommandsRawInput(log, prop, config.OrchestrationDirectory, cancelFlag, config.OutputS3BucketName, config.OutputS3KeyPrefix) } // TODO: instance here we have to do more result processing, where individual sub properties results are merged smartly into plugin response. // Currently assuming we have only one work. if len(properties) > 0 { res.Code = out[0].ExitCode res.Status = out[0].Status res.Output = out[0].String() } pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return res }
// setMsiExecStatus sets the exit status and output to be returned to the user based on exit code func setMsiExecStatus(log log.T, pluginInput ApplicationPluginInput, cancelFlag task.CancelFlag, out *ApplicationPluginOutput) { out.Stdout = pluginInput.Source out.Stderr = "" out.Status = contracts.ResultStatusFailed isUnKnownError := false switch out.ExitCode { case appconfig.SuccessExitCode: out.Status = contracts.ResultStatusSuccess case ErrorUnknownProduct: if pluginInput.Action == UNINSTALL { // Uninstall will skip, if product is not currently installed. // This is needed to support idempotent behavior. out.Status = contracts.ResultStatusSuccess } case ErrorSuccessRebootInitiated: fallthrough case appconfig.RebootExitCode: out.Status = contracts.ResultStatusSuccessAndReboot case pluginutil.CommandStoppedPreemptivelyExitCode: if cancelFlag.ShutDown() { out.Status = contracts.ResultStatusFailed } if cancelFlag.Canceled() { out.Status = contracts.ResultStatusCancelled } out.Status = contracts.ResultStatusTimedOut default: isUnKnownError = true } if isUnKnownError { // Note: Sample Stderr: // Action:{Installed}; Status:{Failed}; // ErrorCode:{1620}; ErrorMsg:{ERROR_INSTALL_PACKAGE_INVALID}; // Description:{This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.}; // Source:{https:///} // Construct stderr in above format using StandardMsiErrorCodes out.Stderr = fmt.Sprintf("Action:{%v}; Status:{%v}; ErrorCode:{%v}; %v Source:{%v};", pluginInput.Action, out.Status, out.ExitCode, getExitCodeDescription(out.ExitCode), pluginInput.Source) } // Logging msiexec.Result log.Debug("logging stdouts & errors after setting final status for msiexec") log.Debugf("resultCode: %v", out.ExitCode) log.Debugf("stdout: %v", out.Stdout) log.Debugf("stderr: %v", out.Stderr) }
// GetStatus returns a ResultStatus variable based on the received exitCode func GetStatus(exitCode int, cancelFlag task.CancelFlag) contracts.ResultStatus { switch exitCode { case appconfig.SuccessExitCode: return contracts.ResultStatusSuccess case CommandStoppedPreemptivelyExitCode: if cancelFlag.ShutDown() { return contracts.ResultStatusFailed } if cancelFlag.Canceled() { return contracts.ResultStatusCancelled } return contracts.ResultStatusTimedOut default: return contracts.ResultStatusFailed } }
// Execute runs multiple sets of commands and returns their outputs. // res.Output will contain a slice of PluginOutput. func (p *Plugin) Execute(context context.T, config contracts.Configuration, cancelFlag task.CancelFlag) (res contracts.PluginResult) { log := context.Log() log.Infof("%v started with configuration %v", Name(), config) res.StartDateTime = time.Now() defer func() { res.EndDateTime = time.Now() }() //loading Properties as list since aws:applications uses properties as list var properties []interface{} if properties, res = pluginutil.LoadParametersAsList(log, config.Properties); res.Code != 0 { pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return res } msiFailureCount := 0 atleastOneRequestedReboot := false finalStdOut := "" finalStdErr := "" out := make([]ApplicationPluginOutput, len(properties)) for i, prop := range properties { // check if a reboot has been requested if rebooter.RebootRequested() { log.Infof("Stopping execution of %v plugin due to an external reboot request.", Name()) return } if cancelFlag.ShutDown() { res.Code = 1 res.Status = contracts.ResultStatusFailed pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return } if cancelFlag.Canceled() { res.Code = 1 res.Status = contracts.ResultStatusCancelled pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return } out[i] = p.runCommandsRawInput(log, prop, config.OrchestrationDirectory, cancelFlag, config.OutputS3BucketName, config.OutputS3KeyPrefix) if out[i].Status == contracts.ResultStatusFailed { msiFailureCount++ if out[i].Stdout != "" { finalStdOut = fmt.Sprintf("%v\n%v", finalStdOut, out[i].Stdout) } if out[i].Stderr != "" { finalStdErr = fmt.Sprintf("%v\n%v", finalStdErr, out[i].Stderr) } } if out[i].Status == contracts.ResultStatusSuccessAndReboot { atleastOneRequestedReboot = true res.Code = out[i].ExitCode } } if atleastOneRequestedReboot { res.Status = contracts.ResultStatusSuccessAndReboot } else { res.Status = contracts.ResultStatusSuccess res.Code = 0 } if msiFailureCount > 0 { finalStdOut = fmt.Sprintf("Number of Failures: %v\n%v", msiFailureCount, finalStdOut) res.Status = contracts.ResultStatusFailed res.Code = 1 } finalOut := contracts.PluginOutput{ Stdout: finalStdOut, Stderr: finalStdErr, } res.Output = finalOut.String() pluginutil.PersistPluginInformationToCurrent(log, Name(), config, res) return res }