feature: bsusurrogate, add StepUpdateBSUBackedVm and StepSnapshotVolumes step
This commit is contained in:
parent
09b899bb84
commit
871df8be85
|
@ -131,7 +131,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
//VMStep
|
||||
|
||||
//omiDevices := b.config.BuildOMIDevices()
|
||||
//launchDevices := b.config.BuildLaunchDevices()
|
||||
launchDevices := b.config.BuildLaunchDevices()
|
||||
|
||||
steps := []multistep.Step{
|
||||
&osccommon.StepPreValidate{
|
||||
|
@ -208,6 +208,13 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
Skip: false,
|
||||
DisableStopVm: b.config.DisableStopVm,
|
||||
},
|
||||
&osccommon.StepUpdateBSUBackedVm{
|
||||
EnableAMISriovNetSupport: b.config.OMISriovNetSupport,
|
||||
EnableAMIENASupport: b.config.OMIENASupport,
|
||||
},
|
||||
&StepSnapshotVolumes{
|
||||
LaunchDevices: launchDevices,
|
||||
},
|
||||
}
|
||||
|
||||
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package bsusurrogate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
osccommon "github.com/hashicorp/packer/builder/osc/common"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/outscale/osc-go/oapi"
|
||||
)
|
||||
|
||||
// StepSnapshotVolumes creates snapshots of the created volumes.
|
||||
//
|
||||
// Produces:
|
||||
// snapshot_ids map[string]string - IDs of the created snapshots
|
||||
type StepSnapshotVolumes struct {
|
||||
LaunchDevices []oapi.BlockDeviceMappingVmCreation
|
||||
snapshotIds map[string]string
|
||||
}
|
||||
|
||||
func (s *StepSnapshotVolumes) snapshotVolume(ctx context.Context, deviceName string, state multistep.StateBag) error {
|
||||
oapiconn := state.Get("oapi").(*oapi.Client)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vm := state.Get("vm").(*oapi.Vm)
|
||||
|
||||
var volumeId string
|
||||
for _, volume := range vm.BlockDeviceMappings {
|
||||
if volume.DeviceName == deviceName {
|
||||
volumeId = volume.Bsu.VolumeId
|
||||
}
|
||||
}
|
||||
if volumeId == "" {
|
||||
return fmt.Errorf("Volume ID for device %s not found", deviceName)
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating snapshot of EBS Volume %s...", volumeId))
|
||||
description := fmt.Sprintf("Packer: %s", time.Now().String())
|
||||
|
||||
createSnapResp, err := oapiconn.POST_CreateSnapshot(oapi.CreateSnapshotRequest{
|
||||
VolumeId: volumeId,
|
||||
Description: description,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the snapshot ID so we can delete it later
|
||||
s.snapshotIds[deviceName] = createSnapResp.OK.Snapshot.SnapshotId
|
||||
|
||||
// Wait for snapshot to be created
|
||||
err = osccommon.WaitUntilSnapshotCompleted(oapiconn, createSnapResp.OK.Snapshot.SnapshotId)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepSnapshotVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
s.snapshotIds = map[string]string{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var errs *multierror.Error
|
||||
for _, device := range s.LaunchDevices {
|
||||
wg.Add(1)
|
||||
go func(device oapi.BlockDeviceMappingVmCreation) {
|
||||
defer wg.Done()
|
||||
if err := s.snapshotVolume(ctx, device.DeviceName, state); err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
}(device)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if errs != nil {
|
||||
state.Put("error", errs)
|
||||
ui.Error(errs.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("snapshot_ids", s.snapshotIds)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSnapshotVolumes) Cleanup(state multistep.StateBag) {
|
||||
if len(s.snapshotIds) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if cancelled || halted {
|
||||
oapiconn := state.Get("oapi").(*oapi.Client)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
ui.Say("Removing snapshots since we cancelled or halted...")
|
||||
for _, snapshotId := range s.snapshotIds {
|
||||
_, err := oapiconn.POST_DeleteSnapshot(oapi.DeleteSnapshotRequest{SnapshotId: snapshotId})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error: %s", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,12 @@ func waitUntilVmStopped(conn *oapi.Client, vmID string) error {
|
|||
return <-errCh
|
||||
}
|
||||
|
||||
func WaitUntilSnapshotCompleted(conn *oapi.Client, vmID string) error {
|
||||
errCh := make(chan error, 1)
|
||||
go waitForState(errCh, "completed", waitUntilSnapshotStateFunc(conn, vmID))
|
||||
return <-errCh
|
||||
}
|
||||
|
||||
func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) error {
|
||||
err := common.Retry(2, 2, 0, func(_ uint) (bool, error) {
|
||||
state, err := refresh()
|
||||
|
@ -77,6 +83,33 @@ func waitUntilVmStateFunc(conn *oapi.Client, id string) stateRefreshFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func waitUntilSnapshotStateFunc(conn *oapi.Client, id string) stateRefreshFunc {
|
||||
return func() (string, error) {
|
||||
log.Printf("[Debug] Check if Snapshot with id %s exists", id)
|
||||
resp, err := conn.POST_ReadSnapshots(oapi.ReadSnapshotsRequest{
|
||||
Filters: oapi.FiltersSnapshot{
|
||||
SnapshotIds: []string{id},
|
||||
},
|
||||
})
|
||||
|
||||
log.Printf("[Debug] Read Response %+v", resp.OK)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.OK == nil {
|
||||
return "", fmt.Errorf("Vm with ID %s. Not Found", id)
|
||||
}
|
||||
|
||||
if len(resp.OK.Snapshots) == 0 {
|
||||
return "pending", nil
|
||||
}
|
||||
|
||||
return resp.OK.Snapshots[0].State, nil
|
||||
}
|
||||
}
|
||||
|
||||
func securityGroupWaitFunc(conn *oapi.Client, id string) stateRefreshFunc {
|
||||
return func() (string, error) {
|
||||
log.Printf("[Debug] Check if SG with id %s exists", id)
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
type StepUpdateBSUBackedVm struct {
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMISriovNetSupport bool
|
||||
}
|
||||
|
||||
func (s *StepUpdateBSUBackedVm) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
// oapiconn := state.Get("oapi").(*oapi.Client)
|
||||
// vm := state.Get("vm").(*oapi.Vm)
|
||||
// ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Set SriovNetSupport to "simple". See http://goo.gl/icuXh5
|
||||
// As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge)
|
||||
// if s.EnableAMISriovNetSupport {
|
||||
// ui.Say("Enabling Enhanced Networking (SR-IOV)...")
|
||||
// simple := "simple"
|
||||
// _, err := oapiconn.POST_UpdateVm(oapi.UpdateVmRequest{
|
||||
// VmId: vm.VmId,
|
||||
// SriovNetSupport: &oapi.AttributeValue{Value: &simple},
|
||||
// })
|
||||
// if err != nil {
|
||||
// err := fmt.Errorf("Error enabling Enhanced Networking (SR-IOV) on %s: %s", *vm.VmId, err)
|
||||
// state.Put("error", err)
|
||||
// ui.Error(err.Error())
|
||||
// return multistep.ActionHalt
|
||||
// }
|
||||
// }
|
||||
|
||||
// Handle EnaSupport flag.
|
||||
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
||||
// if s.EnableAMIENASupport != nil {
|
||||
// var prefix string
|
||||
// if *s.EnableAMIENASupport {
|
||||
// prefix = "En"
|
||||
// } else {
|
||||
// prefix = "Dis"
|
||||
// }
|
||||
// ui.Say(fmt.Sprintf("%sabling Enhanced Networking (ENA)...", prefix))
|
||||
// _, err := oapiconn.UpdateVmAttribute(&oapi.UpdateVmAttributeInput{
|
||||
// VmId: vm.VmId,
|
||||
// EnaSupport: &oapi.AttributeBooleanValue{Value: aws.Bool(*s.EnableAMIENASupport)},
|
||||
// })
|
||||
// if err != nil {
|
||||
// err := fmt.Errorf("Error %sabling Enhanced Networking (ENA) on %s: %s", strings.ToLower(prefix), *vm.VmId, err)
|
||||
// state.Put("error", err)
|
||||
// ui.Error(err.Error())
|
||||
// return multistep.ActionHalt
|
||||
// }
|
||||
// }
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepUpdateBSUBackedVm) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
Loading…
Reference in New Issue