| package devices |
| |
| import ( |
| "context" |
| "fmt" |
| "io" |
| "time" |
| |
| "go.fuchsia.dev/infra/devices/power" |
| "go.fuchsia.dev/tools/netboot" |
| ) |
| |
| // Nuc represents an Intel NUC |
| type Nuc struct { |
| fuchsiaDevice |
| } |
| |
| // NewNuc initializes a NUC for use by other infra utilites. |
| func NewNuc(config DeviceConfig, bootserverCmdStub []string) (*Nuc, error) { |
| n := &Nuc{ |
| fuchsiaDevice{ |
| power: power.NewAMTPowerManager( |
| config.Power.Host, |
| config.Power.Username, |
| config.Power.Password, |
| ), |
| }, |
| } |
| if err := initFuchsiaDevice(&n.fuchsiaDevice, config, bootserverCmdStub); err != nil { |
| return nil, err |
| } |
| |
| // All transitions in a NUC attempt to get it into Zedboot. |
| transitionMap := map[DeviceState]*Transition{ |
| Initial: &Transition{ |
| PerformAction: n.sshRebootRecovery, |
| Validate: n.checkTransitionSuccess, |
| SuccessState: Healthy, |
| FailureState: "ssh_failed", |
| }, |
| "ssh_failed": &Transition{ |
| PerformAction: n.serialRebootRecovery, |
| Validate: n.checkTransitionSuccess, |
| SuccessState: Healthy, |
| FailureState: "serial_failed", |
| }, |
| "serial_failed": &Transition{ |
| PerformAction: n.Powercycle, |
| Validate: n.checkTransitionSuccess, |
| SuccessState: Healthy, |
| FailureState: Unrecoverable, |
| }, |
| } |
| n.transitionMap = transitionMap |
| return n, nil |
| } |
| |
| // checkSerial performs an echo test over serial. |
| func (n *Nuc) checkSerial(ctx context.Context) error { |
| if n.serial == nil { |
| return nil |
| } |
| cmdString := "echo hello" |
| resultString := "\r\n$ echo hello\r\nhello" |
| |
| n.SendSerialCommand(ctx, cmdString) |
| buffer := make([]byte, len(resultString)) |
| if _, err := io.ReadAtLeast(n.serial, buffer, len(resultString)); err != nil { |
| return err |
| } |
| if string(buffer) != resultString { |
| return fmt.Errorf("serial test got unexpected output: %s", string(buffer)) |
| } |
| return nil |
| } |
| |
| // checkTransitionSuccess is the validation function used by all transitions |
| // on a NUC. It checks that serial works and the NUC is in Zedboot. |
| func (n *Nuc) checkTransitionSuccess(ctx context.Context) error { |
| // Give the device time to transition. |
| time.Sleep(1 * time.Minute) |
| client := netboot.NewClient(netbootTimeout) |
| if err := n.checkSerial(ctx); err != nil { |
| return err |
| } |
| return deviceInZedboot(client, n.nodename) |
| } |
| |
| // ToTaskState moves a NUC into a state in which it can run a test task. |
| func (n *Nuc) ToTaskState(ctx context.Context) error { |
| // This assumes that there is a NUC reboot server running to |
| // deliver the build's version of zedboot. |
| return n.Powercycle(ctx) |
| } |