diff --git a/START.md b/START.md index 12e5db08..845c204c 100644 --- a/START.md +++ b/START.md @@ -125,6 +125,8 @@ module "autospotting" { autospotting_min_on_demand_percentage = "50.0" autospotting_regions_enabled = "eu*,us*" on_demand_price_multiplier = "1.0" + spot_price_buffer_percentage = "10.0" + bidding_policy = "normal" lambda_zipname = "./lambda.zip" lambda_runtime = "python2.7" @@ -224,6 +226,17 @@ Usage of ./autospotting: or if you want to set your bid price to be higher than the on demand price to reduce the chances that your spot instances will be terminated. (default 1) + -spot_price_buffer_percentage float + Percentage Value of the bid above the current spot price. A spot + bid would be placed at a value + current_spot_price * [1 + (spot_price_buffer_percentage/100.0)] . + The main benefit is that it protects the group from running spot instances + that got significantly more expensive than when they were initially launched, + but still somewhat less than the on-demand price. (default 10.0) + -bidding_policy string + Policy choice for spot bid. If set to 'normal', we bid at the + on-demand price. If set to 'aggressive', we bid at a multiple of + the spot price. (default "normal") -regions="": Regions where it should be activated (comma or whitespace separated list, also supports globs), by default it runs on all regions. Example: ./autospotting -regions 'eu-*,us-east-1' diff --git a/autospotting b/autospotting new file mode 100755 index 00000000..3fb2b162 Binary files /dev/null and b/autospotting differ diff --git a/autospotting.go b/autospotting.go index 2654e550..3b1eb872 100644 --- a/autospotting.go +++ b/autospotting.go @@ -42,12 +42,16 @@ func run() { "min_on_demand_number=%d "+ "min_on_demand_percentage=%.1f "+ "allowed_instance_types=%v "+ - "on_demand_price_multiplier=%.2f", + "on_demand_price_multiplier=%.2f"+ + "spot_price_buffer_percentage=%.3f"+ + "bidding_policy=%s", conf.Regions, conf.MinOnDemandNumber, conf.MinOnDemandPercentage, conf.AllowedInstanceTypes, - conf.OnDemandPriceMultiplier) + conf.OnDemandPriceMultiplier, + conf.SpotPriceBufferPercentage, + conf.BiddingPolicy) autospotting.Run(conf.Config) log.Println("Execution completed, nothing left to do") @@ -124,6 +128,18 @@ func (c *cfgData) parseCommandLineFlags() { "\tset your bid price to be higher than the on demand price to reduce the chances that your\n"+ "\tspot instances will be terminated.") + flag.Float64Var(&c.SpotPriceBufferPercentage, "spot_price_buffer_percentage", 10, + "Percentage Value of the bid above the current spot price. A spot bid would be placed at a value :\n"+ + "\tcurrent_spot_price * [1 + (spot_price_buffer_percentage/100.0)]. The main benefit is that\n"+ + "\tit protects the group from running spot instances that got significantly more expensive than\n"+ + "\twhen they were initially launched, but still somewhat less than the on-demand price. Can be\n"+ + "\tenforced using the tag: "+autospotting.SpotPriceBufferPercentageTag+". If the bid exceeds\n"+ + "\tthe on-demand price, we place a bid at on-demand price itself.") + + flag.StringVar(&c.BiddingPolicy, "bidding_policy", "normal", + "Policy choice for spot bid. If set to 'normal', we bid at the on-demand price. If set to 'aggressive',\n"+ + "\twe bid at a percentage value above the spot price. ") + v := flag.Bool("version", false, "Print version number and exit.") flag.Parse() diff --git a/cloudformation/stacks/AutoSpotting/template.json b/cloudformation/stacks/AutoSpotting/template.json index aed6628d..f4d95264 100644 --- a/cloudformation/stacks/AutoSpotting/template.json +++ b/cloudformation/stacks/AutoSpotting/template.json @@ -47,6 +47,16 @@ "Description": "Multiplier for the on-demand price. This is useful for volume discounts or if you want to set your bid price to be higher than the on demand price to reduce the chances that your spot instances will be terminated.", "Type": "Number" }, + "SpotPricePercentageBuffer": { + "Default": "10.0", + "Description": "Percentage Value of the bid above the current spot price. A spot bid would be placed at a value = current_spot_price * [1 + (spot_price_buffer_percentage/100.0)]. The main benefit is that it protects the group from running spot instances that got significantly more expensive than when they were initially launched, but still somewhat less than the on-demand price.", + "Type": "Number" + }, + "BiddingPolicy": { + "Default": "normal", + "Description": "Policy choice for spot bid. If set to 'normal', we bid at the on-demand price. If set to 'aggressive', we bid at a multiple of the spot price.", + "Type": "String" + }, "Regions": { "Default": "", "Description": "Space separated list of regions where it should run (supports globs), in case you may want to limit it to a smaller set of regions. If unset it will run against all available regions. Example: 'us-east-1 eu-*'", @@ -88,6 +98,8 @@ "MIN_ON_DEMAND_NUMBER": { "Ref": "MinOnDemandNumber" }, "MIN_ON_DEMAND_PERCENTAGE": { "Ref": "MinOnDemandPercentage" }, "ON_DEMAND_PRICE_MULTIPLIER": { "Ref": "OnDemandPriceMultiplier" }, + "SPOT_PRICE_BUFFER_PERCENTAGE": { "Ref": "SpotPricePercentageBuffer"}, + "BIDDING_POLICY": { "Ref": "BiddingPolicy"}, "REGIONS": { "Ref": "Regions" }, "ALLOWED_INSTANCE_TYPES": { "Ref": "AllowedInstanceTypes" } } diff --git a/core/autoscaling.go b/core/autoscaling.go index a2527188..90fa009d 100644 --- a/core/autoscaling.go +++ b/core/autoscaling.go @@ -2,14 +2,13 @@ package autospotting import ( "errors" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscaling" + "github.com/aws/aws-sdk-go/service/ec2" "math" "strconv" "strings" "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/autoscaling" - "github.com/aws/aws-sdk-go/service/ec2" ) const ( @@ -23,9 +22,24 @@ const ( // absolute number. OnDemandNumberLong = "autospotting_on_demand_number" + // BiddingPolicyTag stores the bidding policy for the spot instance + BiddingPolicyTag = "autospotting_bidding_policy" + + // SpotPriceBufferPercentageTag stores percentage value above the + // current spot price to place the bid + SpotPriceBufferPercentageTag = "spot_price_buffer_percentage" + // DefaultMinOnDemandValue stores the default on-demand capacity to be kept // running in a group managed by autospotting. DefaultMinOnDemandValue = 0 + + // DefaultSpotPriceBufferPercentage stores the default percentage value + // above the current spot price to place a bid + DefaultSpotPriceBufferPercentage = 10.0 + + // DefaultBiddingPolicy stores the default bidding policy for + // the spot bid on a per-group level + DefaultBiddingPolicy = "normal" ) type autoScalingGroup struct { @@ -60,6 +74,21 @@ func (a *autoScalingGroup) loadPercentageOnDemand(tagValue *string) (int64, bool return DefaultMinOnDemandValue, false } +func (a *autoScalingGroup) loadSpotPriceBufferPercentage(tagValue *string) (float64, bool) { + spotPriceBufferPercentage, err := strconv.ParseFloat(*tagValue, 64) + + if err != nil { + logger.Printf("Error with ParseFloat: %s\n", err.Error()) + return DefaultSpotPriceBufferPercentage, false + } else if spotPriceBufferPercentage <= 0 { + logger.Printf("Ignoring out of range value : %f\n", spotPriceBufferPercentage) + return DefaultSpotPriceBufferPercentage, false + } + + logger.Printf("Loaded SpotPriceBufferPercentage value to %f from tag %s\n", spotPriceBufferPercentage, SpotPriceBufferPercentageTag) + return spotPriceBufferPercentage, true +} + func (a *autoScalingGroup) loadNumberOnDemand(tagValue *string) (int64, bool) { onDemand, err := strconv.Atoi(*tagValue) if err != nil { @@ -88,18 +117,72 @@ func (a *autoScalingGroup) loadConfOnDemand() bool { return done } } - } else { - debug.Println("Couldn't find tag", tagKey) } + debug.Println("Couldn't find tag", tagKey) + } + return false +} + +func (a *autoScalingGroup) loadBiddingPolicy(tagValue *string) (string, bool) { + biddingPolicy := *tagValue + if biddingPolicy != "aggressive" { + return DefaultBiddingPolicy, false + } + + logger.Printf("Loaded BiddingPolicy value with %s from tag %s\n", biddingPolicy, BiddingPolicyTag) + return biddingPolicy, true +} + +func (a *autoScalingGroup) loadConfSpot() bool { + tagValue := a.getTagValue(BiddingPolicyTag) + if tagValue == nil { + debug.Println("Couldn't find tag", BiddingPolicyTag) + return false + } + if newValue, done := a.loadBiddingPolicy(tagValue); done { + a.region.conf.BiddingPolicy = newValue + logger.Println("BiddingPolicy =", a.region.conf.BiddingPolicy) + return done } return false } +func (a *autoScalingGroup) loadConfSpotPrice() bool { + + tagValue := a.getTagValue(SpotPriceBufferPercentageTag) + if tagValue == nil { + return false + } + + newValue, done := a.loadSpotPriceBufferPercentage(tagValue) + if !done { + debug.Println("Couldn't find tag", SpotPriceBufferPercentageTag) + return false + } + + a.region.conf.SpotPriceBufferPercentage = newValue + return done +} + // Add configuration of other elements here: prices, whitelisting, etc func (a *autoScalingGroup) loadConfigFromTags() bool { - if a.loadConfOnDemand() { + resOnDemandConf := a.loadConfOnDemand() + + resSpotConf := a.loadConfSpot() + + resSpotPriceConf := a.loadConfSpotPrice() + + if resOnDemandConf { logger.Println("Found and applied configuration for OnDemand value") + } + if resSpotConf { + logger.Println("Found and applied configuration for Spot Bid") + } + if resSpotPriceConf { + logger.Println("Found and applied configuration for Spot Price") + } + if resOnDemandConf || resSpotConf || resSpotPriceConf { return true } return false @@ -131,6 +214,10 @@ func (a *autoScalingGroup) loadDefaultConfig() bool { done := false a.minOnDemand = DefaultMinOnDemandValue + if a.region.conf.SpotPriceBufferPercentage <= 0 { + a.region.conf.SpotPriceBufferPercentage = DefaultSpotPriceBufferPercentage + } + if a.region.conf.MinOnDemandNumber != 0 { a.minOnDemand, done = a.loadDefaultConfigNumber() } @@ -536,6 +623,20 @@ func (a *autoScalingGroup) getAllowedInstanceTypes(baseInstance *instance) []str } +func (a *autoScalingGroup) getPricetoBid( + baseOnDemandPrice float64, currentSpotPrice float64) float64 { + + logger.Println("BiddingPolicy: ", a.region.conf.BiddingPolicy) + + if a.region.conf.BiddingPolicy == DefaultBiddingPolicy { + logger.Println("Launching spot instance with a bid =", baseOnDemandPrice) + return baseOnDemandPrice + } + + logger.Println("Launching spot instance with a bid =", math.Min(baseOnDemandPrice, currentSpotPrice*(1.0+a.region.conf.SpotPriceBufferPercentage/100.0))) + return math.Min(baseOnDemandPrice, currentSpotPrice*(1.0+a.region.conf.SpotPriceBufferPercentage/100.0)) +} + func (a *autoScalingGroup) launchCheapestSpotInstance( azToLaunchIn *string) error { @@ -569,12 +670,11 @@ func (a *autoScalingGroup) launchCheapestSpotInstance( baseOnDemandPrice := baseInstance.price currentSpotPrice := newInstance.pricing.spot[*azToLaunchIn] - logger.Println("Finished searching for best spot instance in ", *azToLaunchIn) logger.Println("Replacing an on-demand", *baseInstance.InstanceType, "instance having the ondemand price", baseOnDemandPrice) logger.Println("Launching best compatible instance:", newInstanceType, - "with current spot price:", currentSpotPrice) + "with the current spot price:", currentSpotPrice) lc := a.getLaunchConfiguration() @@ -584,7 +684,7 @@ func (a *autoScalingGroup) launchCheapestSpotInstance( *azToLaunchIn) logger.Println("Bidding for spot instance for ", a.name) - return a.bidForSpotInstance(spotLS, baseOnDemandPrice) + return a.bidForSpotInstance(spotLS, a.getPricetoBid(baseOnDemandPrice, currentSpotPrice)) } func (a *autoScalingGroup) loadSpotInstanceRequest( diff --git a/core/autoscaling_test.go b/core/autoscaling_test.go index da8c9457..0e228f87 100644 --- a/core/autoscaling_test.go +++ b/core/autoscaling_test.go @@ -2,12 +2,12 @@ package autospotting import ( "errors" - "reflect" - "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" + "math" + "reflect" + "testing" ) func TestGetTagValue(t *testing.T) { @@ -639,6 +639,14 @@ func TestLoadConfigFromTags(t *testing.T) { Key: aws.String(OnDemandPercentageLong), Value: aws.String("text"), }, + { + Key: aws.String(BiddingPolicyTag), + Value: aws.String("Autospotting"), + }, + { + Key: aws.String(SpotPriceBufferPercentageTag), + Value: aws.String("-15.0"), + }, }, asgInstances: makeInstances(), maxSize: aws.Int64(10), @@ -658,6 +666,14 @@ func TestLoadConfigFromTags(t *testing.T) { Key: aws.String(OnDemandNumberLong), Value: aws.String("-2"), }, + { + Key: aws.String(BiddingPolicyTag), + Value: aws.String("normal"), + }, + { + Key: aws.String(SpotPriceBufferPercentageTag), + Value: aws.String("15.0"), + }, }, asgInstances: makeInstancesWithCatalog( map[string]*instance{ @@ -674,10 +690,20 @@ func TestLoadConfigFromTags(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a := autoScalingGroup{Group: &autoscaling.Group{}} + cfg := &Config{ + BiddingPolicy: "normal", + SpotPriceBufferPercentage: 10.0, + } + a := autoScalingGroup{Group: &autoscaling.Group{}, + region: ®ion{ + name: "us-east-1", + conf: cfg, + }, + } a.Tags = tt.asgTags a.instances = tt.asgInstances a.MaxSize = tt.maxSize + done := a.loadConfigFromTags() if tt.loadingExpected != done { t.Errorf("loadConfigFromTags returned: %t expected %t", done, tt.loadingExpected) @@ -686,6 +712,204 @@ func TestLoadConfigFromTags(t *testing.T) { } } +func TestLoadSpotPriceBufferPercentage(t *testing.T) { + tests := []struct { + name string + tagValue *string + loadingExpected bool + valueExpected float64 + }{ + { + tagValue: aws.String("5.0"), + valueExpected: 5.0, + loadingExpected: true, + }, + { + tagValue: aws.String("TEST"), + valueExpected: 10.0, + loadingExpected: false, + }, + { + tagValue: aws.String("-10.0"), + valueExpected: 10.0, + loadingExpected: false, + }, + } + for _, tt := range tests { + a := autoScalingGroup{Group: &autoscaling.Group{}} + value, loading := a.loadSpotPriceBufferPercentage(tt.tagValue) + + if value != tt.valueExpected || loading != tt.loadingExpected { + t.Errorf("LoadBiddingPolicy returned: %f, expected: %f", value, tt.valueExpected) + } + + } +} + +func TestLoadBiddingPolicy(t *testing.T) { + tests := []struct { + name string + tagValue *string + valueExpected string + }{ + {name: "Loading a false tag", + tagValue: aws.String("aggressive"), + valueExpected: "aggressive", + }, + {name: "Loading a true tag", + tagValue: aws.String("normal"), + valueExpected: "normal", + }, + {name: "Loading a fake tag", + tagValue: aws.String("autospotting"), + valueExpected: "normal", + }, + } + for _, tt := range tests { + a := autoScalingGroup{Group: &autoscaling.Group{}} + value, _ := a.loadBiddingPolicy(tt.tagValue) + + if value != tt.valueExpected { + t.Errorf("LoadBiddingPolicy returned: %s, expected: %s", value, tt.valueExpected) + } + + } +} + +func TestLoadConfSpot(t *testing.T) { + tests := []struct { + name string + asgTags []*autoscaling.TagDescription + loadingExpected bool + valueExpected string + }{ + {name: "Loading a fake tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + }, + loadingExpected: false, + valueExpected: "normal", + }, + {name: "Loading a false tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + { + Key: aws.String(BiddingPolicyTag), + Value: aws.String("aggressive"), + }, + }, + loadingExpected: true, + valueExpected: "aggressive", + }, + {name: "Loading a true tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + { + Key: aws.String(BiddingPolicyTag), + Value: aws.String("normal"), + }, + }, + loadingExpected: false, + valueExpected: "normal", + }, + } + for _, tt := range tests { + cfg := &Config{ + BiddingPolicy: "normal", + } + a := autoScalingGroup{Group: &autoscaling.Group{}, + region: ®ion{ + name: "us-east-1", + conf: cfg, + }, + } + a.Tags = tt.asgTags + done := a.loadConfSpot() + if tt.loadingExpected != done { + t.Errorf("LoadSpotConf retured: %t expected %t", done, tt.loadingExpected) + } else if tt.valueExpected != a.region.conf.BiddingPolicy { + t.Errorf("LoadSpotConf loaded: %s expected %s", a.region.conf.BiddingPolicy, tt.valueExpected) + } + + } +} + +func TestLoadConfSpotPrice(t *testing.T) { + tests := []struct { + name string + asgTags []*autoscaling.TagDescription + loadingExpected bool + valueExpected float64 + }{ + {name: "Loading a fake tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + }, + loadingExpected: false, + valueExpected: 10.0, + }, + {name: "Loading the right tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + { + Key: aws.String(SpotPriceBufferPercentageTag), + Value: aws.String("15.0"), + }, + }, + loadingExpected: true, + valueExpected: 15.0, + }, + {name: "Loading a false tag", + asgTags: []*autoscaling.TagDescription{ + { + Key: aws.String("Name"), + Value: aws.String("asg-test"), + }, + { + Key: aws.String(SpotPriceBufferPercentageTag), + Value: aws.String("-50.0"), + }, + }, + loadingExpected: false, + valueExpected: 10.0, + }, + } + for _, tt := range tests { + cfg := &Config{ + SpotPriceBufferPercentage: 10.0, + } + a := autoScalingGroup{Group: &autoscaling.Group{}, + region: ®ion{ + name: "us-east-1", + conf: cfg, + }, + } + a.Tags = tt.asgTags + done := a.loadConfSpotPrice() + if tt.loadingExpected != done { + t.Errorf("LoadSpotConf retured: %t expected %t", done, tt.loadingExpected) + } else if tt.valueExpected != a.region.conf.SpotPriceBufferPercentage { + t.Errorf("LoadSpotConf loaded: %f expected %f", a.region.conf.SpotPriceBufferPercentage, tt.valueExpected) + } + + } +} + func TestAlreadyRunningInstanceCount(t *testing.T) { tests := []struct { name string @@ -2808,3 +3032,62 @@ func TestGetAllowedInstaceTypes(t *testing.T) { }) } } + +func TestGetPricetoBid(t *testing.T) { + tests := []struct { + spotPercentage float64 + currentSpotPrice float64 + currentOnDemandPrice float64 + policy string + want float64 + }{ + { + spotPercentage: 50.0, + currentSpotPrice: 0.0216, + currentOnDemandPrice: 0.0464, + policy: "aggressive", + want: 0.0324, + }, + { + spotPercentage: 79.0, + currentSpotPrice: 0.0216, + currentOnDemandPrice: 0.0464, + policy: "aggressive", + want: 0.038664, + }, + { + spotPercentage: 79.0, + currentSpotPrice: 0.0216, + currentOnDemandPrice: 0.0464, + policy: "normal", + want: 0.0464, + }, + { + spotPercentage: 200.0, + currentSpotPrice: 0.0216, + currentOnDemandPrice: 0.0464, + policy: "aggressive", + want: 0.0464, + }, + } + for _, tt := range tests { + cfg := &Config{ + SpotPriceBufferPercentage: tt.spotPercentage, + BiddingPolicy: tt.policy, + } + asg := &autoScalingGroup{ + region: ®ion{ + name: "us-east-1", + conf: cfg, + }, + } + + currentSpotPrice := tt.currentSpotPrice + currentOnDemandPrice := tt.currentOnDemandPrice + actualPrice := asg.getPricetoBid(currentOnDemandPrice, currentSpotPrice) + if math.Abs(actualPrice-tt.want) > 0.000001 { + t.Errorf("percentage = %.2f, policy = %s, expected price = %.5f, want %.5f, currentSpotPrice = %.5f", + tt.spotPercentage, tt.policy, actualPrice, tt.want, currentSpotPrice) + } + } +} diff --git a/core/config.go b/core/config.go index 1b825a15..a51d7be6 100644 --- a/core/config.go +++ b/core/config.go @@ -21,11 +21,13 @@ type Config struct { // The region where the Lambda function is deployed MainRegion string - MinOnDemandNumber int64 - MinOnDemandPercentage float64 - Regions string - AllowedInstanceTypes string - OnDemandPriceMultiplier float64 + MinOnDemandNumber int64 + MinOnDemandPercentage float64 + Regions string + AllowedInstanceTypes string + OnDemandPriceMultiplier float64 + SpotPriceBufferPercentage float64 + BiddingPolicy string // This is only here for tests, where we want to be able to somehow mock // time.Sleep without actually sleeping. While testing it defaults to 0 (which won't sleep at all), in diff --git a/terraform/autospotting.tf b/terraform/autospotting.tf index 7fcd9810..cca3d3c8 100644 --- a/terraform/autospotting.tf +++ b/terraform/autospotting.tf @@ -1,10 +1,12 @@ module "autospotting" { source = "./autospotting" - autospotting_min_on_demand_number = "${var.asg_min_on_demand_number}" - autospotting_min_on_demand_percentage = "${var.asg_min_on_demand_percentage}" - autospotting_on_demand_price_multiplier = "${var.asg_on_demand_price_multiplier}" - autospotting_regions_enabled = "${var.asg_regions_enabled}" + autospotting_min_on_demand_number = "${var.asg_min_on_demand_number}" + autospotting_min_on_demand_percentage = "${var.asg_min_on_demand_percentage}" + autospotting_on_demand_price_multiplier = "${var.asg_on_demand_price_multiplier}" + autospotting_spot_price_buffer_percentage = "${var.asg_spot_price_buffer_percentage}" + autospotting_bidding_policy = "${var.asg_bidding_policy}" + autospotting_regions_enabled = "${var.asg_regions_enabled}" lambda_zipname = "${var.lambda_zipname}" lambda_runtime = "${var.lambda_runtime}" diff --git a/terraform/autospotting/lambda.tf b/terraform/autospotting/lambda.tf index e8c26716..3d1be154 100644 --- a/terraform/autospotting/lambda.tf +++ b/terraform/autospotting/lambda.tf @@ -10,10 +10,12 @@ resource "aws_lambda_function" "autospotting" { environment { variables = { - MIN_ON_DEMAND_NUMBER = "${var.autospotting_min_on_demand_number}" - MIN_ON_DEMAND_PERCENTAGE = "${var.autospotting_min_on_demand_percentage}" - ON_DEMAND_PRICE_MULTIPLIER = "${var.autospotting_on_demand_price_multiplier}" - REGIONS = "${var.autospotting_regions_enabled}" + MIN_ON_DEMAND_NUMBER = "${var.autospotting_min_on_demand_number}" + MIN_ON_DEMAND_PERCENTAGE = "${var.autospotting_min_on_demand_percentage}" + ON_DEMAND_PRICE_MULTIPLIER = "${var.autospotting_on_demand_price_multiplier}" + SPOT_PRICE_BUFFER_PERCENTAGE = "${var.autospotting_spot_price_buffer_percentage}" + BIDDING_POLICY = "${var.autospotting_bidding_policy}" + REGIONS = "${var.autospotting_regions_enabled}" } } } diff --git a/terraform/autospotting/variables.tf b/terraform/autospotting/variables.tf index 5dc45efc..ec3e3bdb 100644 --- a/terraform/autospotting/variables.tf +++ b/terraform/autospotting/variables.tf @@ -11,6 +11,14 @@ variable "autospotting_on_demand_price_multiplier" { description = "Multiplier for the on-demand price" } +variable "autospotting_spot_price_buffer_percentage" { + description = "Percentage above the current spot price to place the bid" +} + +variable "autospotting_bidding_policy" { + description = "Bidding policy for the spot bid" +} + variable "autospotting_regions_enabled" { description = "Regions that autospotting is watching" } diff --git a/terraform/variables.tf b/terraform/variables.tf index eefbd758..442cd169 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -14,6 +14,16 @@ variable "asg_on_demand_price_multiplier" { default = "1.0" } +variable "asg_spot_price_buffer_percentage" { + description = "Percentage above the current spot price to place the bid" + default = "10.0" +} + +variable "asg_bidding_policy" { + description = "Choice of bidding policy for the spot instance" + default = "normal" +} + variable "asg_regions_enabled" { description = "Regions in which autospotting is enabled" default = ""