Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Launch Templates #2

Merged
merged 3 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions cmd/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ func launchInteractive(h *ec2helper.EC2Helper) {
// Ask for confirmation or modification. Keep asking until the config is confirmed or denied
var detailedConfig *config.DetailedInfo
var confirmation string
var capacityTypeAnswer string
for {
// Parse config first
detailedConfig, err = h.ParseConfig(simpleConfig)
Expand All @@ -161,8 +160,7 @@ func launchInteractive(h *ec2helper.EC2Helper) {
}

// Ask for and set the capacity type
capacityTypeAnswer = question.AskCapacityType()
simpleConfig.CapacityType = capacityTypeAnswer
simpleConfig.CapacityType = question.AskCapacityType()

// Ask for confirmation or modification
confirmation = question.AskConfirmationWithInput(simpleConfig, detailedConfig, true)
Expand Down Expand Up @@ -279,7 +277,7 @@ func LaunchCapacityInstance(h *ec2helper.EC2Helper, simpleConfig *config.SimpleI
if simpleConfig.CapacityType == question.DefaultCapacityTypeText.OnDemand {
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
} else {
err = h.LaunchSpotInstance(simpleConfig, detailedConfig, confirmation)
err = h.LaunchSpotInstance(simpleConfig, detailedConfig, confirmation, nil)
}
return
}
Expand Down Expand Up @@ -337,13 +335,14 @@ func UseLaunchTemplateWithConfig(h *ec2helper.EC2Helper, simpleConfig *config.Si

// Launch an instance with a launch template
func LaunchWithLaunchTemplate(h *ec2helper.EC2Helper, simpleConfig *config.SimpleInfo) {
simpleConfig.CapacityType = question.AskCapacityType()
confirmation, err := question.AskConfirmationWithTemplate(h, simpleConfig)
if cli.ShowError(err, "Asking confirmation with launch template failed") {
return
}

// Launch the instance.
_, err = h.LaunchInstance(simpleConfig, nil, *confirmation == cli.ResponseYes)
err = LaunchCapacityInstance(h, simpleConfig, nil, *confirmation)
if cli.ShowError(err, "Launching instance failed") {
return
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
require (
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
Expand Down
68 changes: 66 additions & 2 deletions pkg/ec2helper/ec2helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import (
"github.com/aws/amazon-ec2-instance-selector/v2/pkg/instancetypes"
"github.com/aws/amazon-ec2-instance-selector/v2/pkg/selector"
"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"
"github.com/google/uuid"
)

const DefaultRegion = "us-east-2"
Expand Down Expand Up @@ -1164,9 +1166,24 @@ func (h *EC2Helper) LaunchInstance(simpleConfig *config.SimpleInfo, detailedConf
}
}

func (h *EC2Helper) LaunchSpotInstance(simpleConfig *config.SimpleInfo, detailedConfig *config.DetailedInfo, confirmation string) (err error) {
func (h *EC2Helper) LaunchSpotInstance(simpleConfig *config.SimpleInfo, detailedConfig *config.DetailedInfo, confirmation string, template *ec2.LaunchTemplate) (err error) {
fmt.Println("Spot Instance Testing")
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
if template != nil {
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes) // Replace with CreateFleet
} else {
template, err = h.CreateLaunchTemplate(simpleConfig)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
fmt.Println(aerr.Error())
} else {
fmt.Println(err.Error())
}
return
}
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes) // Replace with CreateFleet
err = h.DeleteLaunchTemplate(template.LaunchTemplateId)
}

return
}

Expand Down Expand Up @@ -1339,3 +1356,50 @@ func HasEbsVolume(image *ec2.Image) bool {

return false
}

func (h *EC2Helper) CreateLaunchTemplate(simpleConfig *config.SimpleInfo) (template *ec2.LaunchTemplate, err error) {
launchIdentifier := uuid.New()

fmt.Println("Creating Launch Template...")
input := &ec2.CreateLaunchTemplateInput{
LaunchTemplateData: &ec2.RequestLaunchTemplateData{
ImageId: &simpleConfig.ImageId,
InstanceType: &simpleConfig.InstanceType,
NetworkInterfaces: []*ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{
{
AssociatePublicIpAddress: aws.Bool(true),
DeviceIndex: aws.Int64(0),
Ipv6AddressCount: aws.Int64(1),
SubnetId: aws.String(simpleConfig.SubnetId),
},
},
},
TagSpecifications: []*ec2.TagSpecification{
{
ResourceType: aws.String("launch-template"),
Tags: []*ec2.Tag{
{
Key: aws.String("Name"),
Value: aws.String("Ec2-LaunchTemplate"),
},
},
},
},
LaunchTemplateName: aws.String(fmt.Sprintf("SimpleEC2LaunchTemplate-%s", launchIdentifier)),
VersionDescription: aws.String(fmt.Sprintf("Lauch Template %s", launchIdentifier)),
}

result, err := h.Svc.CreateLaunchTemplate(input)
template = result.LaunchTemplate
return
}

func (h *EC2Helper) DeleteLaunchTemplate(templateId *string) (err error) {
fmt.Println("Deleting Launch Template...")
input := &ec2.DeleteLaunchTemplateInput{
LaunchTemplateId: templateId,
}

_, err = h.Svc.DeleteLaunchTemplate(input)
return
}
30 changes: 30 additions & 0 deletions pkg/ec2helper/ec2helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ func TestGetAvailableAvailabilityZones_NoResult(t *testing.T) {
Launch Template Tests
*/

var testLaunchId = "lt-12345"

func TestGetLaunchTemplatesInRegion_Success(t *testing.T) {
expectedTemplates := []*ec2.LaunchTemplate{
{
Expand Down Expand Up @@ -225,6 +227,34 @@ func TestGetLaunchTemplateById_DescribeLaunchTemplatesPagesError(t *testing.T) {
th.Nok(t, err)
}

func TestCreateLaunchTemplate(t *testing.T) {
config := config.NewSimpleInfo()
config.ImageId = "ami-12345"
config.InstanceType = "t2.micro"
config.SubnetId = "subnet-12345"
testEC2.Svc = &th.MockedEC2Svc{}
testEC2.CreateLaunchTemplate(config)

launchTemplatesOutput, _ := testEC2.Svc.DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{})
templates := launchTemplatesOutput.LaunchTemplates
th.Equals(t, 1, len(templates))
th.Equals(t, testLaunchId, *templates[0].LaunchTemplateId)
}

func TestDeleteLaunchTemplate(t *testing.T) {
testEC2.Svc = &th.MockedEC2Svc{
LaunchTemplates: []*ec2.LaunchTemplate{
{LaunchTemplateId: &testLaunchId},
},
}
testEC2.DeleteLaunchTemplate(&testLaunchId)

launchTemplatesOutput, _ := testEC2.Svc.DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{})
templates := launchTemplatesOutput.LaunchTemplates

th.Equals(t, 0, len(templates))
}

/*
Launch Template Version Tests
*/
Expand Down
3 changes: 3 additions & 0 deletions pkg/ec2helper/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type EC2Svc interface {
RunInstances(input *ec2.RunInstancesInput) (*ec2.Reservation, error)
TerminateInstances(input *ec2.TerminateInstancesInput) (*ec2.TerminateInstancesOutput, error)
DeleteSecurityGroup(input *ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error)
CreateLaunchTemplate(input *ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error)
DeleteLaunchTemplate(input *ec2.DeleteLaunchTemplateInput) (*ec2.DeleteLaunchTemplateOutput, error)
DescribeLaunchTemplates(input *ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error)
GavinBurris42 marked this conversation as resolved.
Show resolved Hide resolved
}

type EC2Helper struct {
Expand Down
27 changes: 27 additions & 0 deletions test/testhelper/ec2helper_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,33 @@ func findFilter(filters []*ec2.Filter, name string) []*string {
return nil
}

func (e *MockedEC2Svc) CreateLaunchTemplate(input *ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) {
output := &ec2.CreateLaunchTemplateOutput{
LaunchTemplate: &ec2.LaunchTemplate{
LaunchTemplateId: aws.String("lt-12345"),
},
}
e.LaunchTemplates = append(e.LaunchTemplates, output.LaunchTemplate)
return output, nil
}

func (e *MockedEC2Svc) DeleteLaunchTemplate(input *ec2.DeleteLaunchTemplateInput) (*ec2.DeleteLaunchTemplateOutput, error) {
for index, template := range e.LaunchTemplates {
if *template.LaunchTemplateId == "lt-12345" {
e.LaunchTemplates = append(e.LaunchTemplates[:index], e.LaunchTemplates[index+1:]...)
return nil, nil
}
}
return nil, nil
}

func (e *MockedEC2Svc) DescribeLaunchTemplates(input *ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error) {
output := &ec2.DescribeLaunchTemplatesOutput{
LaunchTemplates: e.LaunchTemplates,
}
return output, nil
}

// Placeholder functions
func (e *MockedEC2Svc) DeleteSecurityGroup(input *ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error) {
return nil, nil
Expand Down