2019-10-14 10:43:59 -04:00
|
|
|
//go:generate mapstructure-to-hcl2 -type Config
|
|
|
|
|
2016-07-07 17:50:46 -04:00
|
|
|
package googlecomputeexport
|
|
|
|
|
|
|
|
import (
|
2019-03-22 09:56:02 -04:00
|
|
|
"context"
|
2016-07-07 17:50:46 -04:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2019-10-31 10:49:34 -04:00
|
|
|
"time"
|
2016-07-07 17:50:46 -04:00
|
|
|
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/builder/googlecompute"
|
|
|
|
"github.com/hashicorp/packer/common"
|
|
|
|
"github.com/hashicorp/packer/helper/config"
|
2018-01-19 19:18:44 -05:00
|
|
|
"github.com/hashicorp/packer/helper/multistep"
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/packer"
|
|
|
|
"github.com/hashicorp/packer/template/interpolate"
|
2019-07-02 19:16:13 -04:00
|
|
|
"golang.org/x/oauth2/jwt"
|
2016-07-07 17:50:46 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
common.PackerConfig `mapstructure:",squash"`
|
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
AccountFile string `mapstructure:"account_file"`
|
|
|
|
|
2019-09-20 19:52:35 -04:00
|
|
|
DiskSizeGb int64 `mapstructure:"disk_size"`
|
|
|
|
DiskType string `mapstructure:"disk_type"`
|
|
|
|
MachineType string `mapstructure:"machine_type"`
|
|
|
|
Network string `mapstructure:"network"`
|
|
|
|
Paths []string `mapstructure:"paths"`
|
|
|
|
Subnetwork string `mapstructure:"subnetwork"`
|
|
|
|
VaultGCPOauthEngine string `mapstructure:"vault_gcp_oauth_engine"`
|
|
|
|
Zone string `mapstructure:"zone"`
|
2016-07-07 17:50:46 -04:00
|
|
|
|
2019-10-14 10:19:17 -04:00
|
|
|
account *jwt.Config
|
2019-01-22 12:34:01 -05:00
|
|
|
ctx interpolate.Context
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type PostProcessor struct {
|
|
|
|
config Config
|
|
|
|
runner multistep.Runner
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PostProcessor) Configure(raws ...interface{}) error {
|
|
|
|
err := config.Decode(&p.config, &config.DecodeOpts{
|
|
|
|
Interpolate: true,
|
|
|
|
InterpolateContext: &p.config.ctx,
|
|
|
|
}, raws...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
errs := new(packer.MultiError)
|
|
|
|
|
|
|
|
if len(p.config.Paths) == 0 {
|
|
|
|
errs = packer.MultiErrorAppend(
|
|
|
|
errs, fmt.Errorf("paths must be specified"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set defaults.
|
|
|
|
if p.config.DiskSizeGb == 0 {
|
|
|
|
p.config.DiskSizeGb = 200
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.config.DiskType == "" {
|
|
|
|
p.config.DiskType = "pd-ssd"
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.config.MachineType == "" {
|
|
|
|
p.config.MachineType = "n1-highcpu-4"
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.config.Network == "" && p.config.Subnetwork == "" {
|
|
|
|
p.config.Network = "default"
|
|
|
|
}
|
|
|
|
|
2019-09-20 19:52:35 -04:00
|
|
|
if p.config.AccountFile != "" && p.config.VaultGCPOauthEngine != "" {
|
|
|
|
errs = packer.MultiErrorAppend(
|
|
|
|
errs, fmt.Errorf("May set either account_file or "+
|
|
|
|
"vault_gcp_oauth_engine, but not both."))
|
|
|
|
}
|
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
if len(errs.Errors) > 0 {
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
2016-07-07 17:50:46 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-08 13:59:42 -04:00
|
|
|
func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) {
|
2016-07-07 17:50:46 -04:00
|
|
|
if artifact.BuilderId() != googlecompute.BuilderId {
|
|
|
|
err := fmt.Errorf(
|
|
|
|
"Unknown artifact type: %s\nCan only export from Google Compute Engine builder artifacts.",
|
|
|
|
artifact.BuilderId())
|
2019-04-03 15:05:38 -04:00
|
|
|
return nil, false, false, err
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
builderAccountFile := artifact.State("AccountFilePath").(string)
|
|
|
|
builderImageName := artifact.State("ImageName").(string)
|
|
|
|
builderProjectId := artifact.State("ProjectId").(string)
|
|
|
|
builderZone := artifact.State("BuildZone").(string)
|
2016-07-07 17:50:46 -04:00
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
ui.Say(fmt.Sprintf("Exporting image %v to destination: %v", builderImageName, p.config.Paths))
|
|
|
|
|
|
|
|
if p.config.Zone == "" {
|
|
|
|
p.config.Zone = builderZone
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up credentials for GCE driver.
|
|
|
|
if builderAccountFile != "" {
|
2019-07-02 19:16:13 -04:00
|
|
|
cfg, err := googlecompute.ProcessAccountFile(builderAccountFile)
|
2019-01-22 12:34:01 -05:00
|
|
|
if err != nil {
|
2019-04-03 15:05:38 -04:00
|
|
|
return nil, false, false, err
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|
2019-10-14 10:19:17 -04:00
|
|
|
p.config.account = cfg
|
2019-01-22 12:34:01 -05:00
|
|
|
}
|
|
|
|
if p.config.AccountFile != "" {
|
2019-07-02 19:16:13 -04:00
|
|
|
cfg, err := googlecompute.ProcessAccountFile(p.config.AccountFile)
|
2016-07-07 17:50:46 -04:00
|
|
|
if err != nil {
|
2019-04-03 15:05:38 -04:00
|
|
|
return nil, false, false, err
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|
2019-10-14 10:19:17 -04:00
|
|
|
p.config.account = cfg
|
2019-01-22 12:34:01 -05:00
|
|
|
}
|
2016-07-07 17:50:46 -04:00
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
// Set up exporter instance configuration.
|
|
|
|
exporterName := fmt.Sprintf("%s-exporter", artifact.Id())
|
|
|
|
exporterMetadata := map[string]string{
|
|
|
|
"image_name": builderImageName,
|
|
|
|
"name": exporterName,
|
|
|
|
"paths": strings.Join(p.config.Paths, " "),
|
|
|
|
"startup-script": StartupScript,
|
|
|
|
"zone": p.config.Zone,
|
|
|
|
}
|
|
|
|
exporterConfig := googlecompute.Config{
|
|
|
|
DiskName: exporterName,
|
|
|
|
DiskSizeGb: p.config.DiskSizeGb,
|
|
|
|
DiskType: p.config.DiskType,
|
|
|
|
InstanceName: exporterName,
|
|
|
|
MachineType: p.config.MachineType,
|
|
|
|
Metadata: exporterMetadata,
|
|
|
|
Network: p.config.Network,
|
2019-03-01 09:12:31 -05:00
|
|
|
NetworkProjectId: builderProjectId,
|
2019-10-31 10:49:34 -04:00
|
|
|
StateTimeout: 5 * time.Minute,
|
2019-01-22 12:34:01 -05:00
|
|
|
SourceImageFamily: "debian-9-worker",
|
|
|
|
SourceImageProjectId: "compute-image-tools",
|
|
|
|
Subnetwork: p.config.Subnetwork,
|
|
|
|
Zone: p.config.Zone,
|
|
|
|
Scopes: []string{
|
|
|
|
"https://www.googleapis.com/auth/compute",
|
|
|
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
|
|
|
"https://www.googleapis.com/auth/userinfo.email",
|
|
|
|
},
|
|
|
|
}
|
2016-07-07 17:50:46 -04:00
|
|
|
|
2019-09-20 19:52:35 -04:00
|
|
|
driver, err := googlecompute.NewDriverGCE(ui, builderProjectId,
|
2019-10-14 10:19:17 -04:00
|
|
|
p.config.account, p.config.VaultGCPOauthEngine)
|
2019-01-22 12:34:01 -05:00
|
|
|
if err != nil {
|
2019-04-03 15:05:38 -04:00
|
|
|
return nil, false, false, err
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|
|
|
|
|
2019-01-22 12:34:01 -05:00
|
|
|
// Set up the state.
|
|
|
|
state := new(multistep.BasicStateBag)
|
|
|
|
state.Put("config", &exporterConfig)
|
|
|
|
state.Put("driver", driver)
|
|
|
|
state.Put("ui", ui)
|
|
|
|
|
|
|
|
// Build the steps.
|
|
|
|
steps := []multistep.Step{
|
|
|
|
&googlecompute.StepCreateSSHKey{
|
|
|
|
Debug: p.config.PackerDebug,
|
|
|
|
DebugKeyPath: fmt.Sprintf("gce_%s.pem", p.config.PackerBuildName),
|
|
|
|
},
|
|
|
|
&googlecompute.StepCreateInstance{
|
|
|
|
Debug: p.config.PackerDebug,
|
|
|
|
},
|
|
|
|
new(googlecompute.StepWaitStartupScript),
|
|
|
|
new(googlecompute.StepTeardownInstance),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the steps.
|
|
|
|
p.runner = common.NewRunner(steps, p.config.PackerConfig, ui)
|
2019-03-22 09:56:02 -04:00
|
|
|
p.runner.Run(ctx, state)
|
2019-01-22 12:34:01 -05:00
|
|
|
|
|
|
|
result := &Artifact{paths: p.config.Paths}
|
|
|
|
|
2019-04-03 15:05:38 -04:00
|
|
|
return result, false, false, nil
|
2016-07-07 17:50:46 -04:00
|
|
|
}
|