in awsiotjobs/mender/mender.go [73:152]
func (mj *Job) exec(cmd mendercmd.Commander, timeout time.Duration) error {
switch mj.Operation {
case "mender_install":
// check if we are back after rebooting
switch mj.menderState.Step {
case "rebooting":
mj.reportProgress("rebooted")
// This is a naive implementation. Before committing one would probably check the system is working fine
// and then issue the Commit, otherwise Rollback.
// For example, in case Greengrass was installed, one could check that Greengrass service is up
// and running.
// On the other hand, to come to this stage, we know that we have network, time and date and we can connect
// to AWS.
err := cmd.Commit() // commit
if err != nil {
jobErr := awsiotjobs.JobError{ErrCode: "ERR_MENDER_COMMIT", ErrMessage: "error committing"}
mj.fail(jobErr)
return jobErr
}
mj.success("committed")
default:
// If the step is "installing" it could be for different cases
// 1- the system rebooted/lost connection and the installation was not completed.
// 2- Installation was completed, system rebooted, but the state update was not performed
// In case 1 we should restart the installation process
// In case 2 we should either make sure this does not happen - ie make the reboot conditional to the
// correct persistance of the "rebooting" state; or rely on some other mechanism to detect that the
// firmware has been successfully updated and the system has rebooted and is working correctly
ch := make(chan string)
done := make(chan error)
mj.progress("installing")
go cmd.Install(mj.URL, done, ch)
for {
select {
case progress := <-ch:
log.Printf("%s", progress)
mj.reportProgress(progress) // report progress via MQTT
case err := <-done:
if err != nil {
jobErr := awsiotjobs.JobError{ErrCode: "ERR_MENDER_INSTALL_FAILED", ErrMessage: err.Error()}
mj.fail(jobErr)
return jobErr
}
// This should be changed - setting the rebooting state might fail
// and when the system startsup will find a wrong state and will start installing the software again
// Must find a way to make this deterministic - maybe relying on mender local state?
mj.progress("rebooting")
go func() {
cmd := exec.Command("shutdown", "-r", "now")
cmd.Start()
err := cmd.Wait()
if err != nil {
fmt.Println("Could not reboot the system")
mj.fail(awsiotjobs.JobError{ErrCode: "ERROR_UNABLE_TO_REBOOT", ErrMessage: err.Error()})
return
}
fmt.Println("rebooting...")
mj.execution.Terminate() //Should be called by the agent code and not the library - based on signalling from the OS when shutting down
}()
return nil
case <-time.After(timeout): // timeout value can be in doc
fmt.Printf("install timeout")
jobErr := awsiotjobs.JobError{ErrCode: "ERR_MENDER_INSTALL_TIMEOUT", ErrMessage: "mender timed out"}
mj.fail(jobErr)
return jobErr
}
}
}
case "mender_rollback":
err := cmd.Rollback()
if err != nil {
mj.fail(awsiotjobs.JobError{ErrCode: "ERR_MENDER_ROLLBACK_FAIL", ErrMessage: "unable to run rollback"})
return err
}
mj.success("rolled_back")
}
return nil
}