mirror of https://github.com/hashicorp/packer
commit
65bd7207e8
@ -0,0 +1,131 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
// Define a mock struct to be used in unit tests for common aws steps.
|
||||
type mockEC2ConnSpot struct {
|
||||
ec2iface.EC2API
|
||||
Config *aws.Config
|
||||
|
||||
// Counters to figure out what code path was taken
|
||||
describeSpotPriceHistoryCount int
|
||||
}
|
||||
|
||||
// Generates fake SpotPriceHistory data and returns it in the expected output
|
||||
// format. Also increments a
|
||||
func (m *mockEC2ConnSpot) DescribeSpotPriceHistory(copyInput *ec2.DescribeSpotPriceHistoryInput) (*ec2.DescribeSpotPriceHistoryOutput, error) {
|
||||
m.describeSpotPriceHistoryCount++
|
||||
testTime := time.Now().Add(-1 * time.Hour)
|
||||
sp := []*ec2.SpotPrice{
|
||||
{
|
||||
AvailabilityZone: aws.String("us-east-1c"),
|
||||
InstanceType: aws.String("t2.micro"),
|
||||
ProductDescription: aws.String("Linux/UNIX"),
|
||||
SpotPrice: aws.String("0.003500"),
|
||||
Timestamp: &testTime,
|
||||
},
|
||||
{
|
||||
AvailabilityZone: aws.String("us-east-1f"),
|
||||
InstanceType: aws.String("t2.micro"),
|
||||
ProductDescription: aws.String("Linux/UNIX"),
|
||||
SpotPrice: aws.String("0.003500"),
|
||||
Timestamp: &testTime,
|
||||
},
|
||||
{
|
||||
AvailabilityZone: aws.String("us-east-1b"),
|
||||
InstanceType: aws.String("t2.micro"),
|
||||
ProductDescription: aws.String("Linux/UNIX"),
|
||||
SpotPrice: aws.String("0.003500"),
|
||||
Timestamp: &testTime,
|
||||
},
|
||||
}
|
||||
output := &ec2.DescribeSpotPriceHistoryOutput{SpotPriceHistory: sp}
|
||||
|
||||
return output, nil
|
||||
|
||||
}
|
||||
|
||||
func getMockConnSpot() ec2iface.EC2API {
|
||||
mockConn := &mockEC2ConnSpot{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
|
||||
return mockConn
|
||||
}
|
||||
|
||||
// Create statebag for running test
|
||||
func tStateSpot() multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packer.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
state.Put("availability_zone", "us-east-1c")
|
||||
state.Put("securityGroupIds", []string{"sg-0b8984db72f213dc3"})
|
||||
state.Put("subnet_id", "subnet-077fde4e")
|
||||
state.Put("source_image", "")
|
||||
return state
|
||||
}
|
||||
|
||||
func getBasicStep() *StepRunSpotInstance {
|
||||
stepRunSpotInstance := StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: false,
|
||||
BlockDevices: BlockDevices{
|
||||
AMIBlockDevices: AMIBlockDevices{
|
||||
AMIMappings: []BlockDevice(nil),
|
||||
},
|
||||
LaunchBlockDevices: LaunchBlockDevices{
|
||||
LaunchMappings: []BlockDevice(nil),
|
||||
},
|
||||
},
|
||||
BlockDurationMinutes: 0,
|
||||
Debug: false,
|
||||
Comm: &communicator.Config{
|
||||
SSHKeyPairName: "foo",
|
||||
},
|
||||
EbsOptimized: false,
|
||||
ExpectedRootDevice: "ebs",
|
||||
IamInstanceProfile: "",
|
||||
InstanceInitiatedShutdownBehavior: "stop",
|
||||
InstanceType: "t2.micro",
|
||||
SourceAMI: "",
|
||||
SpotPrice: "auto",
|
||||
SpotPriceProduct: "Linux/UNIX",
|
||||
SpotTags: TagMap(nil),
|
||||
Tags: TagMap{},
|
||||
VolumeTags: TagMap(nil),
|
||||
UserData: "",
|
||||
UserDataFile: "",
|
||||
}
|
||||
|
||||
return &stepRunSpotInstance
|
||||
}
|
||||
func TestCalculateSpotPrice(t *testing.T) {
|
||||
stepRunSpotInstance := getBasicStep()
|
||||
// Set spot price and spot price product
|
||||
stepRunSpotInstance.SpotPrice = "auto"
|
||||
stepRunSpotInstance.SpotPriceProduct = "Linux/UNIX"
|
||||
ec2conn := getMockConnSpot()
|
||||
// state := tStateSpot()
|
||||
spotPrice, err := stepRunSpotInstance.CalculateSpotPrice("", ec2conn)
|
||||
if err != nil {
|
||||
t.Fatalf("Should not have had an error calculating spot price")
|
||||
}
|
||||
sp, _ := strconv.ParseFloat(spotPrice, 64)
|
||||
expected := 0.008500
|
||||
if sp != expected { // 0.003500 (from spot history) + .005
|
||||
t.Fatalf("Expected spot price of \"0.008500\", not %s", spotPrice)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
- `spot_instance_types` (array of strings) - a list of acceptable instance
|
||||
types to run your build on. We will request a spot instance using the max
|
||||
price of `spot_price` and the allocation strategy of "lowest price".
|
||||
Your instance will be launched on an instance type of the lowest available
|
||||
price that you have in your list. This is used in place of instance_type.
|
||||
You may only set either spot_instance_types or instance_type, not both.
|
||||
This feature exists to help prevent situations where a Packer build fails
|
||||
because a particular availability zone does not have capacity for the
|
||||
specific instance_type requested in instance_type.
|
||||
|
||||
- `spot_price` (string) - The maximum hourly price to pay for a spot instance
|
||||
to create the AMI. Spot instances are a type of instance that EC2 starts
|
||||
when the current spot price is less than the maximum price you specify.
|
||||
Spot price will be updated based on available spot instance capacity and
|
||||
current spot instance requests. It may save you some costs. You can set
|
||||
this to `auto` for Packer to automatically discover the best spot price or
|
||||
to "0" to use an on demand instance (default).
|
||||
|
||||
- `spot_price_auto_product` (string) - Required if `spot_price` is set to
|
||||
`auto`. This tells Packer what sort of AMI you're launching to find the
|
||||
best spot price. This must be one of: `Linux/UNIX`, `SUSE Linux`,
|
||||
`Windows`, `Linux/UNIX (Amazon VPC)`, `SUSE Linux (Amazon VPC)`,
|
||||
`Windows (Amazon VPC)`
|
||||
|
||||
- `spot_tags` (object of key/value strings) - Requires `spot_price` to be
|
||||
set. This tells Packer to apply tags to the spot request that is issued.
|
||||
Loading…
Reference in new issue