func()

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
}