func()

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
}