func (a *AWSCloud) TerminateInstance(instanceID string) error {
	if a.useLocalhost {
		klog.Infof("Skipping termination as locahost")
		return nil
	}
	request := &ec2.TerminateInstancesInput{}
	request.InstanceIds = []*string{&instanceID}
	klog.V(2).Infof("AWS TerminateInstances instanceID=%q", instanceID)
	_, err := a.ec2.TerminateInstances(request)
	return err
}
TerminateInstance terminates the specified instance
package imagebuilder
import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"sync"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"golang.org/x/crypto/ssh"
	"k8s.io/klog"
	"sigs.k8s.io/image-builder/images/kube-deploy/imagebuilder/pkg/imagebuilder/executor"
)
const tagRoleKey = "k8s.io/role/imagebuilder"
type AWSInstance struct {
	instanceID string
	cloud      *AWSCloud
	instance   *ec2.Instance
}
var _ Instance = &AWSInstance{}
func (i *AWSInstance) Shutdown() error {
	klog.Infof("Terminating instance %q", i.instanceID)
	return i.cloud.TerminateInstance(i.instanceID)
}
func (i *AWSInstance) DialSSH(config *ssh.ClientConfig) (executor.Executor, error) {
	publicIP, err := i.WaitPublicIP()
	if err != nil {
		return nil, err
	}
	for {
		sshClient, err := ssh.Dial("tcp", publicIP+":22", config)
		if err != nil {
			klog.Warningf("error connecting to SSH on server %q: %v", publicIP, err)
			time.Sleep(5 * time.Second)
			continue
		}
		return executor.NewSSH(sshClient), nil
	}
}
func (i *AWSInstance) WaitPublicIP() (string, error) {
	for {
		instance, err := i.cloud.describeInstance(i.instanceID)
		if err != nil {
			return "", err
		}
		publicIP := aws.StringValue(instance.PublicIpAddress)
		if publicIP != "" {
			klog.Infof("Instance public IP is %q", publicIP)
			return publicIP, nil
		}
		klog.V(2).Infof("Sleeping before requerying instance for public IP: %q", i.instanceID)
		time.Sleep(5 * time.Second)
	}
}
type LocalhostInstance struct {
	cloud Cloud
}
func (i *LocalhostInstance) Shutdown() error {
	klog.Infof("Skipping termination of localhost")
	return nil
}
func (i *LocalhostInstance) DialSSH(config *ssh.ClientConfig) (executor.Executor, error) {
	return &executor.LocalhostExecutor{}, nil
}
type AWSCloud struct {
	config *AWSConfig
	ec2 *ec2.EC2
	useLocalhost bool
}
var _ Cloud = &AWSCloud{}
func NewAWSCloud(ec2 *ec2.EC2, config *AWSConfig, useLocalhost bool) *AWSCloud {
	return &AWSCloud{
		ec2:          ec2,
		config:       config,
		useLocalhost: useLocalhost,
	}
}
func (a *AWSCloud) GetExtraEnv() (map[string]string, error) {
	env := make(map[string]string)
	if a.useLocalhost {
		return env, nil
	}
	credentials := a.ec2.Config.Credentials
	if credentials == nil {
		return nil, fmt.Errorf("unable to determine EC2 credentials")
	}
	creds, err := credentials.Get()
	if err != nil {
		return nil, fmt.Errorf("error fetching EC2 credentials: %v", err)
	}
	if a.config.InstanceProfile == "" {
		env["AWS_ACCESS_KEY_ID"] = creds.AccessKeyID
		env["AWS_SECRET_ACCESS_KEY"] = creds.SecretAccessKey
		env["AWS_SESSION_TOKEN"] = creds.SessionToken
		env["AWS_SECURITY_TOKEN"] = creds.SessionToken
	}
	return env, nil
}
func (a *AWSCloud) describeInstance(instanceID string) (*ec2.Instance, error) {
	request := &ec2.DescribeInstancesInput{}
	request.InstanceIds = []*string{&instanceID}
	klog.V(2).Infof("AWS DescribeInstances InstanceId=%q", instanceID)
	response, err := a.ec2.DescribeInstances(request)
	if err != nil {
		return nil, fmt.Errorf("error making AWS DescribeInstances call: %v", err)
	}
	for _, reservation := range response.Reservations {
		for _, instance := range reservation.Instances {
			if aws.StringValue(instance.InstanceId) != instanceID {
				panic("Unexpected InstanceId found")
			}
			return instance, err
		}
	}
	return nil, nil
}