// Create registers an AMI from an existing snapshot and optionally makes the AMI publically available
func (d *SDKCreateAmiDriver) Create(driverConfig resources.AmiDriverConfig) (resources.Ami, error) {
	var err error

	createStartTime := time.Now()
	defer func(startTime time.Time) {
		d.logger.Printf("completed Create() in %f minutes\n", time.Since(startTime).Minutes())
	}(createStartTime)

	d.logger.Printf("creating AMI from snapshot: %s\n", driverConfig.SnapshotID)
	amiName := driverConfig.Name

	var reqInput *ec2.RegisterImageInput
	switch driverConfig.VirtualizationType {
	case resources.PvAmiVirtualization:
		kernelID, err := d.findLatestKernelImage()
		if err != nil {
			return resources.Ami{}, fmt.Errorf("generating register image request for PV AMI: %s", err)
		}

		reqInput = reqinputs.NewPVAmiRequest(amiName, driverConfig.Description, driverConfig.SnapshotID, kernelID)
	case resources.HvmAmiVirtualization:
		reqInput = reqinputs.NewHVMAmiRequestInput(amiName, driverConfig.Description, driverConfig.SnapshotID)
	}

	reqOutput, err := d.ec2Client.RegisterImage(reqInput)
	if err != nil {
		return resources.Ami{}, fmt.Errorf("registering AMI: %s", err)
	}

	amiIDptr := reqOutput.ImageId
	if amiIDptr == nil {
		return resources.Ami{}, errors.New("AMI id nil")
	}

	d.logger.Printf("waiting for AMI: %s to exist\n", *amiIDptr)
	err = d.ec2Client.WaitUntilImageExists(&ec2.DescribeImagesInput{
		ImageIds: []*string{amiIDptr},
	})
	if err != nil {
		return resources.Ami{}, fmt.Errorf("waiting for AMI %s to exist: %s", *amiIDptr, err)
	}

	d.logger.Printf("waiting for AMI: %s to be available\n", *amiIDptr)
	err = d.ec2Client.WaitUntilImageAvailable(&ec2.DescribeImagesInput{
		ImageIds: []*string{amiIDptr},
	})
	if err != nil {
		return resources.Ami{}, fmt.Errorf("waiting for AMI %s to be available: %s", *amiIDptr, err)
	}

	if driverConfig.Accessibility == resources.PublicAmiAccessibility {
		d.logger.Printf("making AMI: %s public", *amiIDptr)
		d.ec2Client.ModifyImageAttribute(&ec2.ModifyImageAttributeInput{
			ImageId: amiIDptr,
			LaunchPermission: &ec2.LaunchPermissionModifications{
				Add: []*ec2.LaunchPermission{
					&ec2.LaunchPermission{
						Group: aws.String(publicGroup),
					},
				},
			},
		})
	}

	ami := resources.Ami{
		ID:                 *amiIDptr,
		Region:             d.region,
		VirtualizationType: driverConfig.VirtualizationType,
	}

	return ami, nil
}
package reqinputs_test

import (
	"light-stemcell-builder/driver/reqinputs"
	"light-stemcell-builder/resources"

	"github.com/aws/aws-sdk-go/service/ec2"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("building inputs for register image", func() {
	Describe("NewHVMAmiRequestInput", func() {
		It("builds valid request input for building an HVM AMI", func() {
			input := reqinputs.NewHVMAmiRequestInput("some-ami-name", "some-ami-description", "some-snapshot-id")
			Expect(input).To(BeAssignableToTypeOf(&ec2.RegisterImageInput{}))
			Expect(*input.SriovNetSupport).To(Equal("simple"))
			Expect(*input.Architecture).To(Equal(resources.AmiArchitecture))
			Expect(*input.Description).To(Equal("some-ami-description"))
			Expect(*input.VirtualizationType).To(Equal(resources.HvmAmiVirtualization))
			Expect(*input.Name).To(Equal("some-ami-name"))
			Expect(*input.RootDeviceName).To(Equal("/dev/xvda"))
			Expect(input.BlockDeviceMappings).To(HaveLen(1))
			Expect(*input.BlockDeviceMappings[0].DeviceName).To(Equal("/dev/xvda"))
			Expect(*input.BlockDeviceMappings[0].Ebs.SnapshotId).To(Equal("some-snapshot-id"))
			Expect(*input.BlockDeviceMappings[0].Ebs.DeleteOnTermination).To(BeTrue())
		})
	})

	Describe("NewPVAmiRequest", func() {
		It("builds valid request input for building an PV AMI", func() {