in updater/aws.go [326:386]
func (u *updater) updateInstance(inst instance) error {
log.Printf("Starting update on instance %q", inst.instanceID)
ec2IDs := []string{inst.instanceID}
log.Printf("Checking current update state of instance %q", inst.instanceID)
commandID, err := u.sendCommand(ec2IDs, u.checkDocument)
if err != nil {
return fmt.Errorf("failed to send check command: %w", err)
}
output, err := u.getCommandResult(commandID, inst.instanceID)
if err != nil {
return fmt.Errorf("failed to get check command output: %w", err)
}
check, err := parseCommandOutput(output)
if err != nil {
return fmt.Errorf("failed to parse command output %q: %w", string(output), err)
}
switch check.UpdateState {
case updateStateIdle:
log.Printf("No new update available for instance %q", inst.instanceID)
return nil
case updateStateStaged:
return fmt.Errorf("unexpected update state %q; skipping instance", check.UpdateState)
case updateStateAvailable:
log.Printf("Starting update apply on instance %q", inst.instanceID)
_, err := u.sendCommand(ec2IDs, u.applyDocument)
if err != nil {
return fmt.Errorf("failed to send update apply command: %w", err)
}
case updateStateReady:
log.Printf("Update is previously applied on instance %q", inst.instanceID)
default:
return fmt.Errorf("unknown update state %q", check.UpdateState)
}
// occasionally instance goes into reboot before reporting command output, therefore
// we do not poll for command output. Instead we rely on verifyUpdate to confirm update
// success or failure.
log.Printf("Sending SSM document %q on instance %q", u.rebootDocument, inst.instanceID)
// SendCommand is directly called here because we do not want to wait on command complete.
resp, err := u.ssm.SendCommand(&ssm.SendCommandInput{
DocumentName: aws.String(u.rebootDocument),
DocumentVersion: aws.String("$DEFAULT"),
InstanceIds: aws.StringSlice(ec2IDs),
TimeoutSeconds: aws.Int64(deliveryTimeoutSeconds),
})
if err != nil {
return fmt.Errorf("failed to send reboot command: %w", err)
}
rebootID := *resp.Command.CommandId
log.Printf("SSM document %q posted with command ID %q", u.rebootDocument, rebootID)
// added some sleep time for reboot to start before we check instance state
time.Sleep(15 * time.Second)
err = u.waitUntilOk(inst.instanceID)
if err != nil {
return fmt.Errorf("failed to reach Ok status after reboot: %w", err)
}
return nil
}