Skip to content

Commit

Permalink
Add support for launching Spot instances (#85)
Browse files Browse the repository at this point in the history
* Changed year default format for tag value message

* Added new SpotOrOnDemand question to simple-ec2

* Refactored Capacity Type question and included capacity type in launch table

* Added and modified tests to test the new CapacityType question

* Capacity Question formatting

* Added struct for capacity type terms

* Correcting PR issues due Capacity question

* PR changes to restructure methods

* Created functions for creating and deleting Launch Templates. Added these methods into flow on creating a spot instance

* Created mocks and tests for testing creating and deleting Launch Templates

* Addressed issues to Creating and Deleting launch templates from PR. Fixed issues with Launch Template tests as well

* Added CreateFleet method. Restructured LaunchTemplate testing methods to use an existing mock method.

* Refactored tests for creating and deleting launch templates

* Formatted the CLI output when a Spot instance is created

* Created tests for using CreateFleet to create a Spot instance

* Added security groups and subnet to launch template allowing spot instances to be connectable. Also fixed bug so launch templates can create spot instances.

* Configured spot instances to include VPC, subnet, security groups, EBS configuration, tags, auto-termination, and other configurations

* Revised duplicate code with data configuration struct

* Refactored Request Instance configuration struct

* Added real time pricing for spot and onDemand instances for Capacity type question

* Update pkg/ec2helper/ec2helper.go

Co-authored-by: Steve Nay <265958+snay2@users.noreply.github.com>

* Update pkg/question/question.go

Co-authored-by: Steve Nay <265958+snay2@users.noreply.github.com>

Co-authored-by: Burris <ggburris@bcd0741c1a87.ant.amazon.com>
Co-authored-by: Steve Nay <265958+snay2@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 29, 2022
1 parent 8b9e8ae commit 20ee196
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 77 deletions.
30 changes: 25 additions & 5 deletions cmd/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ func launchInteractive(h *ec2helper.EC2Helper) {
return
}

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

// Ask for confirmation or modification
confirmation = question.AskConfirmationWithInput(simpleConfig, detailedConfig, true)

Expand Down Expand Up @@ -209,8 +212,9 @@ func launchInteractive(h *ec2helper.EC2Helper) {
}
}

// Launch the instance.
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
// Launch On-Demand or Spot instance based on capacity type
err = LaunchCapacityInstance(h, simpleConfig, detailedConfig, confirmation)

if cli.ShowError(err, "Launching instance failed") {
return
}
Expand Down Expand Up @@ -260,14 +264,26 @@ func launchNonInteractive(h *ec2helper.EC2Helper) {

confirmation := question.AskConfirmationWithInput(simpleConfig, detailedConfig, false)

// Launch the instance.
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
LaunchCapacityInstance(h, simpleConfig, detailedConfig, confirmation)

if cli.ShowError(err, "Launching instance failed") {
return
}
ReadSaveConfig(simpleConfig)
}

// Launch On-Demand or Spot instance based on capacity type
func LaunchCapacityInstance(h *ec2helper.EC2Helper, simpleConfig *config.SimpleInfo, detailedConfig *config.DetailedInfo,
confirmation string) error {
var err error
if simpleConfig.CapacityType == question.DefaultCapacityTypeText.OnDemand {
_, err = h.LaunchInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
} else {
err = h.LaunchSpotInstance(simpleConfig, detailedConfig, confirmation == cli.ResponseYes)
}
return err
}

// Validate flags using some simple rules. Return true if the flags are validated, false otherwise
func ValidateLaunchFlags(flags *config.SimpleInfo) bool {
if flags.LaunchTemplateVersion != "" && flags.LaunchTemplateId == "" {
Expand Down Expand Up @@ -321,13 +337,17 @@ func UseLaunchTemplateWithConfig(h *ec2helper.EC2Helper, simpleConfig *config.Si

// Launch an instance with a launch template
func LaunchWithLaunchTemplate(h *ec2helper.EC2Helper, simpleConfig *config.SimpleInfo) {
versions, err := h.GetLaunchTemplateVersions(simpleConfig.LaunchTemplateId,
&simpleConfig.LaunchTemplateVersion)
templateData := versions[0].LaunchTemplateData
simpleConfig.CapacityType = question.AskCapacityType(*templateData.InstanceType)
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +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
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
1 change: 1 addition & 0 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const (
ResourceIamInstanceProfile = "IAM Instance Profile"
ResourceBootScriptFilePath = "Boot Script Filepath"
ResourceUserTags = "Tag Specification(key|value)"
ResourceCapacityType = "Capacity Type"
)

// Show errors if there are any. Return true when there are errors, and false when there is none
Expand Down
14 changes: 14 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type SimpleInfo struct {
IamInstanceProfile string
BootScriptFilePath string
UserTags map[string]string
CapacityType string
}

/*
Expand All @@ -62,6 +63,19 @@ type DetailedInfo struct {
TagSpecs []*ec2.TagSpecification
}

type RequestInstanceInfo struct {
ImageId *string
InstanceType *string
SubnetId *string
SecurityGroupIds []*string
IamInstanceProfile *ec2.IamInstanceProfileSpecification
LaunchTemplate *ec2.LaunchTemplateSpecification
BlockDeviceMappings []*ec2.BlockDeviceMapping
LaunchTemplateBlockMappings []*ec2.LaunchTemplateBlockDeviceMappingRequest
InstanceInitiatedShutdownBehavior *string
UserData *string
}

func NewSimpleInfo() *SimpleInfo {
var s SimpleInfo
s.UserTags = make(map[string]string)
Expand Down
5 changes: 4 additions & 1 deletion pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ const testLaunchTemplateVersion = "1"
const testNewVPC = true
const testIamProfile = "iam-profile"
const testBootScriptFilePath = "some/path/to/bootscript"
const testCapacityType = "On-Spot-Demand"

var testTags = map[string]string{"testedBy": "BRYAN", "brokenBy": "CBASKIN"}
var testSecurityGroup = []string{"sg-12345", "sg-67890"}

const expectedJson = `{"Region":"us-somewhere","ImageId":"ami-12345","InstanceType":"t2.micro","SubnetId":"s-12345","LaunchTemplateId":"lt-12345","LaunchTemplateVersion":"1","SecurityGroupIds":["sg-12345","sg-67890"],"NewVPC":true,"AutoTerminationTimerMinutes":0,"KeepEbsVolumeAfterTermination":false,"IamInstanceProfile":"iam-profile","BootScriptFilePath":"some/path/to/bootscript","UserTags":{"brokenBy":"CBASKIN","testedBy":"BRYAN"}}`
const expectedJson = `{"Region":"us-somewhere","ImageId":"ami-12345","InstanceType":"t2.micro","SubnetId":"s-12345","LaunchTemplateId":"lt-12345","LaunchTemplateVersion":"1","SecurityGroupIds":["sg-12345","sg-67890"],"NewVPC":true,"AutoTerminationTimerMinutes":0,"KeepEbsVolumeAfterTermination":false,"IamInstanceProfile":"iam-profile","BootScriptFilePath":"some/path/to/bootscript","UserTags":{"brokenBy":"CBASKIN","testedBy":"BRYAN"},"CapacityType":"On-Spot-Demand"}`

func TestSaveConfig(t *testing.T) {
testConfig := &config.SimpleInfo{
Expand All @@ -72,6 +73,7 @@ func TestSaveConfig(t *testing.T) {
IamInstanceProfile: testIamProfile,
BootScriptFilePath: testBootScriptFilePath,
UserTags: testTags,
CapacityType: testCapacityType,
}

err := config.SaveConfig(testConfig, aws.String(testConfigFileName))
Expand Down Expand Up @@ -126,6 +128,7 @@ func TestReadConfig(t *testing.T) {
IamInstanceProfile: testIamProfile,
BootScriptFilePath: testBootScriptFilePath,
UserTags: testTags,
CapacityType: testCapacityType,
}
th.Equals(t, expectedConfig, actualConfig)
}
Loading

0 comments on commit 20ee196

Please sign in to comment.