From bc907f0fd07f3810553000c1f11163575436d3f8 Mon Sep 17 00:00:00 2001 From: Marin Salinas Date: Thu, 21 Feb 2019 15:57:07 -0600 Subject: [PATCH] feature: add vm info step --- builder/osc/chroot/builder.go | 45 +++++++++++++++++++++ builder/osc/chroot/command.go | 15 +++++++ builder/osc/chroot/step_vm_info.go | 64 ++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 builder/osc/chroot/command.go create mode 100644 builder/osc/chroot/step_vm_info.go diff --git a/builder/osc/chroot/builder.go b/builder/osc/chroot/builder.go index 2feb8083e..12a83bc0c 100644 --- a/builder/osc/chroot/builder.go +++ b/builder/osc/chroot/builder.go @@ -5,8 +5,10 @@ package chroot import ( + "crypto/tls" "errors" "log" + "net/http" "runtime" osccommon "github.com/hashicorp/packer/builder/osc/common" @@ -15,6 +17,7 @@ import ( "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template/interpolate" + "github.com/outscale/osc-go/oapi" ) // The unique ID for this builder @@ -184,6 +187,48 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe if runtime.GOOS != "linux" { return nil, errors.New("The outscale-chroot builder only works on Linux environments.") } + + clientConfig, err := b.config.Config() + if err != nil { + return nil, err + } + + skipClient := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } + + oapiconn := oapi.NewClient(clientConfig, skipClient) + + wrappedCommand := func(command string) (string, error) { + ctx := b.config.ctx + ctx.Data = &wrappedCommandTemplate{Command: command} + return interpolate.Render(b.config.CommandWrapper, &ctx) + } + + // Setup the state bag and initial state for the steps + state := new(multistep.BasicStateBag) + state.Put("config", &b.config) + state.Put("oapi", oapiconn) + state.Put("clientConfig", clientConfig) + state.Put("hook", hook) + state.Put("ui", ui) + state.Put("wrappedCommand", CommandWrapper(wrappedCommand)) + + // Build the steps + steps := []multistep.Step{ + &osccommon.StepPreValidate{ + DestOmiName: b.config.OMIName, + ForceDeregister: b.config.OMIForceDeregister, + }, + &StepVmInfo{}, + } + + // Run! + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) + b.runner.Run(state) + return nil, nil } diff --git a/builder/osc/chroot/command.go b/builder/osc/chroot/command.go new file mode 100644 index 000000000..0ca55be67 --- /dev/null +++ b/builder/osc/chroot/command.go @@ -0,0 +1,15 @@ +package chroot + +import ( + "os/exec" +) + +// CommandWrapper is a type that given a command, will possibly modify that +// command in-flight. This might return an error. +type CommandWrapper func(string) (string, error) + +// ShellCommand takes a command string and returns an *exec.Cmd to execute +// it within the context of a shell (/bin/sh). +func ShellCommand(command string) *exec.Cmd { + return exec.Command("/bin/sh", "-c", command) +} diff --git a/builder/osc/chroot/step_vm_info.go b/builder/osc/chroot/step_vm_info.go new file mode 100644 index 000000000..0104e2f48 --- /dev/null +++ b/builder/osc/chroot/step_vm_info.go @@ -0,0 +1,64 @@ +package chroot + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" + "github.com/outscale/osc-go/oapi" +) + +// StepVmInfo verifies that this builder is running on an Outscale vm. +type StepVmInfo struct{} + +func (s *StepVmInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + oapiconn := state.Get("oapi").(*oapi.Client) + //session := state.Get("clientConfig").(*session.Session) + ui := state.Get("ui").(packer.Ui) + + // Get our own vm ID + ui.Say("Gathering information about this Outscale vm...") + + cmd := ShellCommand("curl http://169.254.169.254/latest/meta-data/instance-id") + + vmID, err := cmd.Output() + if err != nil { + err := fmt.Errorf( + "Error retrieving the ID of the vm Packer is running on.\n" + + "Please verify Packer is running on a proper Outscale vm.") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + log.Printf("[Debug] VmID got: %s", string(vmID)) + + // Query the entire vm metadata + resp, err := oapiconn.POST_ReadVms(oapi.ReadVmsRequest{Filters: oapi.FiltersVm{ + VmIds: []string{string(vmID)}, + }}) + if err != nil { + err := fmt.Errorf("Error getting vm data: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + vmsResp := resp.OK + + if len(vmsResp.Vms) == 0 { + err := fmt.Errorf("Error getting vm data: no vm found.") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + vm := vmsResp.Vms[0] + state.Put("vm", vm) + + return multistep.ActionContinue +} + +func (s *StepVmInfo) Cleanup(multistep.StateBag) {}