Skip to content

Commit

Permalink
Allow fast boot disable on region (#509)
Browse files Browse the repository at this point in the history
* ebs: add fast-launch toggle on regions

The fast-launch configuration allows setupping fast-launch for Windows
virtual machines, either with a common configuration, or with a
region-by-region configuration.
However if someone wants to only enable fast-launch on a subset of
regions, there wasn't any way to express that, leading to either a waste
of resources, or a need to manually cleanup the extra snapshots created.

Therefore this commit adds an extra trilean to the regional
configuration for fast-launch, so it can be explicitly disabled on
selected regions.

* ebs: parallelise fast-launch tests with copy

Those tests are long-running, and can run concurrently as they don't use
the same resources, so in order to reduce the length of running those
tests, we enable parallelisation on them.
  • Loading branch information
lbajolet-hashicorp authored Sep 16, 2024
1 parent 08064f8 commit 5b8dfdf
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 9 deletions.
12 changes: 12 additions & 0 deletions .web-docs/components/builder/ebs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,18 @@ https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-ami-config-fast-launc

<!-- Code generated from the comments of the FastLaunchTemplateConfig struct in builder/ebs/fast_launch_setup.go; DO NOT EDIT MANUALLY -->

- `enable_fast_launch` (boolean) - Enable fast launch allows you to disable fast launch settings on the region level.

If unset, the default region behavior will be assumed - i.e. either use
the globally specified template ID/name (if specified), or AWS will set
it for you.

Using other fast launch options, while unset, will imply enable_fast_launch to be true.

If this is explicitly set to `false` fast-launch will be
disabled for the specified region and all other options besides region
will be ignored.

- `template_id` (string) - The ID of the launch template to use for the fast launch

This cannot be specified in conjunction with the template name.
Expand Down
80 changes: 75 additions & 5 deletions builder/ebs/builder_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,7 @@ func TestAccBuilder_EbsWindowsFastLaunch(t *testing.T) {
func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) {
amiNameWithoutLT := fmt.Sprintf("packer-ebs-windows-fastlaunch-with-copies-%d", time.Now().Unix())
amiNameWithLT := fmt.Sprintf("packer-ebs-windows-fastlaunch-with-copies-and-launch-templates-%d", time.Now().Unix())
amiNameWithLTOneSkipped := fmt.Sprintf("packer-ebs-windows-fastlaunch-with-one-copy-disabled-%d", time.Now().Unix())

flWithCopiesAMIs := []amazon_acc.AMIHelper{
{
Expand All @@ -1168,6 +1169,12 @@ func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) {
Name: amiNameWithLT,
},
}
flWithCopiesAMIOneSkipped := []amazon_acc.AMIHelper{
{
Region: "us-east-1",
Name: amiNameWithLTOneSkipped,
},
}

tests := []struct {
name string
Expand Down Expand Up @@ -1197,17 +1204,31 @@ func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) {
},
testWindowsFastBootWithAMICopiesAndLTs,
},
{
"ebs-windows-fast-launch-with-copies-one-region-disabled",
amiNameWithLTOneSkipped,
flWithCopiesAMIOneSkipped,
[]string{
"found template in region \"us-east-1\": ID \"lt-0c82d8943c032fc0b\"",
"fast-launch explicitly disabled for region \"us-east-2\"",
},
testWindowsFastBootWithAMICopiesAndLTsOneDisabled,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
currtest := tt

t.Parallel()

testcase := &acctest.PluginTestCase{
Name: tt.name,
Template: fmt.Sprintf(tt.template, tt.amiName),
Name: currtest.name,
Template: fmt.Sprintf(currtest.template, currtest.amiName),
Teardown: func() error {
var errs error

for _, ami := range tt.amiSpec {
for _, ami := range currtest.amiSpec {
err := ami.CleanUpAmi()
if err != nil {
t.Logf("cleaning up AMI %q in region %q failed: %s. It will need to be manually removed", ami.Name, ami.Region, err)
Expand All @@ -1222,7 +1243,7 @@ func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) {
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
}

for _, ami := range tt.amiSpec {
for _, ami := range currtest.amiSpec {
amis, err := ami.GetAmi()
if err != nil {
return fmt.Errorf("failed to get AMI: %s", err)
Expand Down Expand Up @@ -1270,7 +1291,7 @@ func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) {
t.Fatalf("failed to read logs from logifle: %s", err)
}
logStr := string(logs)
for _, str := range tt.stringsToFindInLog {
for _, str := range currtest.stringsToFindInLog {
if !strings.Contains(logStr, str) {
t.Errorf("exptected to find %q in logs, but did not", str)
}
Expand Down Expand Up @@ -2065,6 +2086,55 @@ build {
}
`

const testWindowsFastBootWithAMICopiesAndLTsOneDisabled = `
data "amazon-ami" "windows-ami" {
filters = {
name = "Windows_Server-2016-English-Core-Base-*"
}
owners = ["801119661308"]
most_recent = true
region = "us-east-1"
}
source "amazon-ebs" "windows-fastboot" {
ami_name = "%s"
source_ami = data.amazon-ami.windows-ami.id
instance_type = "m3.medium"
region = "us-east-1"
ami_regions = ["us-east-2", "us-east-1"]
communicator = "winrm"
winrm_username = "Administrator"
winrm_password = "e4sypa55!"
user_data_file = "test-fixtures/ps_enable.ps"
fast_launch {
enable_fast_launch = true
target_resource_count = 1
region_launch_templates {
region = "us-east-1"
template_id = "lt-0c82d8943c032fc0b"
}
region_launch_templates {
region = "us-east-2"
enable_fast_launch = false
}
}
}
build {
sources = ["amazon-ebs.windows-fastboot"]
provisioner "powershell" {
inline = [
"C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule",
"C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown"
]
}
}
`

const testSubnetFilterWithPublicIP = `
source "amazon-ebs" "test-subnet-filter" {
subnet_filter {
Expand Down
20 changes: 20 additions & 0 deletions builder/ebs/fast_launch_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ package ebs
import (
"fmt"
"log"

"github.com/hashicorp/packer-plugin-sdk/template/config"
)

// FastLaunchTemplateConfig is the launch template configuration for a region.
Expand All @@ -17,6 +19,18 @@ import (
// in the template, as each fast-launch enablement step occurs after the
// copy, and each region may pick their own launch template.
type FastLaunchTemplateConfig struct {
// Enable fast launch allows you to disable fast launch settings on the region level.
//
// If unset, the default region behavior will be assumed - i.e. either use
// the globally specified template ID/name (if specified), or AWS will set
// it for you.
//
// Using other fast launch options, while unset, will imply enable_fast_launch to be true.
//
// If this is explicitly set to `false` fast-launch will be
// disabled for the specified region and all other options besides region
// will be ignored.
EnableFalseLaunch config.Trilean `mapstructure:"enable_fast_launch"`
// The region in which to find the launch template to use
Region string `mapstructure:"region" required:"true"`
// The ID of the launch template to use for the fast launch
Expand Down Expand Up @@ -47,6 +61,12 @@ func (tc *FastLaunchTemplateConfig) Prepare() []error {
return append(errs, fmt.Errorf("region cannot be empty for a regional fast template config"))
}

// If we disabled fast-launch, we can immediately exit without validating
// the other options.
if tc.EnableFalseLaunch == config.TriFalse {
return errs
}

if tc.LaunchTemplateID != "" && tc.LaunchTemplateName != "" {
errs = append(errs, fmt.Errorf("fast_launch_template_config region %q: both template ID and name cannot be specified at the same time", tc.Region))
}
Expand Down
10 changes: 6 additions & 4 deletions builder/ebs/fast_launch_setup.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions builder/ebs/step_enable_fast_launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ func (s *stepEnableFastLaunch) Run(ctx context.Context, state multistep.StateBag
go func(region, ami string) {
defer wg.Done()

// Immediately return if we don't want fast-launch for a
// particular region
templateIDsByRegion, ok := state.GetOk("launch_template_version")
if ok && !templateIDsByRegion.(map[string]TemplateSpec)[region].Enabled {
log.Printf("skipping fast launch for region %q", region)
return
}

// Casting is somewhat unsafe, but since the retryer below only
// accepts this type, and not ec2iface.EC2API, we can safely
// do this here, unless the `GetRegionConn` function evolves
Expand Down
14 changes: 14 additions & 0 deletions builder/ebs/step_prepare_fast_launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/hashicorp/packer-plugin-amazon/builder/common"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
)

type stepPrepareFastLaunchTemplate struct {
Expand All @@ -25,6 +26,10 @@ type stepPrepareFastLaunchTemplate struct {
type TemplateSpec struct {
TemplateID string
Version int
// Since this is what gets forwarded to the step that enables fast launch
// for each region, we have to also forward if the option should be disabled
// for a particular region
Enabled bool
}

func (s *stepPrepareFastLaunchTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
Expand All @@ -49,6 +54,14 @@ func (s *stepPrepareFastLaunchTemplate) Run(ctx context.Context, state multistep
for _, templateSpec := range s.RegionTemplates {
region := templateSpec.Region

if templateSpec.EnableFalseLaunch == config.TriFalse {
log.Printf("[INFO] fast-launch explicitly disabled for region %q", region)
templateIDsByRegion[region] = TemplateSpec{
Enabled: false,
}
continue
}

if templateSpec.LaunchTemplateID == "" && templateSpec.LaunchTemplateName == "" {
log.Printf("[INFO] No fast-launch template specified for region %q", region)
continue
Expand All @@ -70,6 +83,7 @@ func (s *stepPrepareFastLaunchTemplate) Run(ctx context.Context, state multistep
ts := TemplateSpec{
TemplateID: *tmpl.LaunchTemplateId,
Version: templateSpec.LaunchTemplateVersion,
Enabled: true,
}

log.Printf("found template in region %q: ID %q, name %q", region, *tmpl.LaunchTemplateId, *tmpl.LaunchTemplateName)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
<!-- Code generated from the comments of the FastLaunchTemplateConfig struct in builder/ebs/fast_launch_setup.go; DO NOT EDIT MANUALLY -->

- `enable_fast_launch` (boolean) - Enable fast launch allows you to disable fast launch settings on the region level.

If unset, the default region behavior will be assumed - i.e. either use
the globally specified template ID/name (if specified), or AWS will set
it for you.

Using other fast launch options, while unset, will imply enable_fast_launch to be true.

If this is explicitly set to `false` fast-launch will be
disabled for the specified region and all other options besides region
will be ignored.

- `template_id` (string) - The ID of the launch template to use for the fast launch

This cannot be specified in conjunction with the template name.
Expand Down

0 comments on commit 5b8dfdf

Please sign in to comment.