1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// The googlecompute package contains a packersdk.Builder implementation that
// builds images for Google Compute Engine.
package googlecompute
import (
"context"
"fmt"
"log"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/packer-plugin-sdk/communicator"
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer/packer-plugin-sdk/multistep/commonsteps"
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
)
// The unique ID for this builder.
const BuilderId = "packer.googlecompute"
// Builder represents a Packer Builder.
type Builder struct {
config Config
runner multistep.Runner
}
func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
return nil, warnings, nil
}
// Run executes a googlecompute Packer build and returns a packersdk.Artifact
// representing a GCE machine image.
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
cfg := GCEDriverConfig{
Ui: ui,
ProjectId: b.config.ProjectId,
Account: b.config.account,
ImpersonateServiceAccountName: b.config.ImpersonateServiceAccount,
VaultOauthEngineName: b.config.VaultGCPOauthEngine,
}
driver, err := NewDriverGCE(cfg)
if err != nil {
return nil, err
}
// Set up the state.
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("driver", driver)
state.Put("hook", hook)
state.Put("ui", ui)
// Build the steps.
steps := []multistep.Step{
new(StepCheckExistingImage),
&communicator.StepSSHKeyGen{
CommConf: &b.config.Comm,
SSHTemporaryKeyPair: b.config.Comm.SSH.SSHTemporaryKeyPair,
},
multistep.If(b.config.PackerDebug && b.config.Comm.SSHPrivateKeyFile == "",
&communicator.StepDumpSSHKey{
Path: fmt.Sprintf("gce_%s.pem", b.config.PackerBuildName),
SSH: &b.config.Comm.SSH,
},
),
&StepImportOSLoginSSHKey{
Debug: b.config.PackerDebug,
},
&StepCreateInstance{
Debug: b.config.PackerDebug,
},
&StepCreateWindowsPassword{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("gce_windows_%s.pem", b.config.PackerBuildName),
},
&StepInstanceInfo{
Debug: b.config.PackerDebug,
},
&StepStartTunnel{
IAPConf: &b.config.IAPConfig,
CommConf: &b.config.Comm,
AccountFile: b.config.AccountFile,
ImpersonateAccount: b.config.ImpersonateServiceAccount,
ProjectId: b.config.ProjectId,
},
&communicator.StepConnect{
Config: &b.config.Comm,
Host: communicator.CommHost(b.config.Comm.Host(), "instance_ip"),
SSHConfig: b.config.Comm.SSHConfigFunc(),
WinRMConfig: winrmConfig,
},
new(commonsteps.StepProvision),
&commonsteps.StepCleanupTempKeys{
Comm: &b.config.Comm,
},
}
if _, exists := b.config.Metadata[StartupScriptKey]; exists || b.config.StartupScriptFile != "" {
steps = append(steps, new(StepWaitStartupScript))
}
steps = append(steps, new(StepTeardownInstance), new(StepCreateImage))
// Run the steps.
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)
// Report any errors.
if rawErr, ok := state.GetOk("error"); ok {
return nil, rawErr.(error)
}
if _, ok := state.GetOk("image"); !ok {
log.Println("Failed to find image in state. Bug?")
return nil, nil
}
artifact := &Artifact{
image: state.Get("image").(*Image),
driver: driver,
config: &b.config,
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
}
return artifact, nil
}
// Cancel.
|