diff --git a/builder/googlecompute/driver_gce.go b/builder/googlecompute/driver_gce.go index ad27c7094..61bb293b7 100644 --- a/builder/googlecompute/driver_gce.go +++ b/builder/googlecompute/driver_gce.go @@ -34,7 +34,7 @@ type driverGCE struct { var DriverScopes = []string{"https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control"} -func NewDriverGCE(ui packer.Ui, p string, a *AccountFile) (Driver, error) { +func NewClientGCE(a *AccountFile) (*http.Client, error) { var err error var client *http.Client @@ -78,6 +78,15 @@ func NewDriverGCE(ui packer.Ui, p string, a *AccountFile) (Driver, error) { return nil, err } + return client, nil +} + +func NewDriverGCE(ui packer.Ui, p string, a *AccountFile) (Driver, error) { + client, err := NewClientGCE(a) + if err != nil { + return nil, err + } + log.Printf("[INFO] Instantiating GCE client...") service, err := compute.New(client) if err != nil { diff --git a/builder/googlecompute/startup.go b/builder/googlecompute/startup.go index 687afec98..18d6961ef 100644 --- a/builder/googlecompute/startup.go +++ b/builder/googlecompute/startup.go @@ -15,7 +15,7 @@ const StartupScriptStatusNotDone string = "notdone" var StartupScriptLinux string = fmt.Sprintf(`#!/usr/bin/env bash echo "Packer startup script starting." RETVAL=0 -BASEMETADATAURL=http://metadata/computeMetadata/v1/instance/ +BASEMETADATAURL=http://metadata.google.internal/computeMetadata/v1/instance/ GetMetadata () { echo "$(curl -f -H "Metadata-Flavor: Google" ${BASEMETADATAURL}/${1} 2> /dev/null)" diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go index 252a2664b..d33ece72e 100644 --- a/builder/hyperv/common/step_create_vm.go +++ b/builder/hyperv/common/step_create_vm.go @@ -61,9 +61,9 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste } // convert the MB to bytes - ramSize := int64(s.RamSize * 1024 * 1024) - diskSize := int64(s.DiskSize * 1024 * 1024) - diskBlockSize := int64(s.DiskBlockSize * 1024 * 1024) + ramSize := int64(s.RamSize) * 1024 * 1024 + diskSize := int64(s.DiskSize) * 1024 * 1024 + diskBlockSize := int64(s.DiskBlockSize) * 1024 * 1024 err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, ramSize, diskSize, diskBlockSize, s.SwitchName, s.Generation, s.DifferencingDisk, s.FixedVHD, s.Version) diff --git a/builder/vmware/common/hw_config.go b/builder/vmware/common/hw_config.go index d740025c2..588d295f1 100644 --- a/builder/vmware/common/hw_config.go +++ b/builder/vmware/common/hw_config.go @@ -14,6 +14,7 @@ type HWConfig struct { // cpu information CpuCount int `mapstructure:"cpus"` MemorySize int `mapstructure:"memory"` + CoreCount int `mapstructure:"cores"` // network type and adapter Network string `mapstructure:"network"` @@ -40,6 +41,11 @@ func (c *HWConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("An invalid amount of memory was specified (memory < 0): %d", c.MemorySize)) } + // Hardware and cpu options + if c.CoreCount < 0 { + errs = append(errs, fmt.Errorf("An invalid number of cores was specified (cores < 0): %d", c.CoreCount)) + } + // Peripherals if !c.Sound { c.Sound = false diff --git a/builder/vmware/common/hw_config_test.go b/builder/vmware/common/hw_config_test.go index be884b144..3532dc1b9 100644 --- a/builder/vmware/common/hw_config_test.go +++ b/builder/vmware/common/hw_config_test.go @@ -8,6 +8,7 @@ import ( func testHWConfig() *HWConfig { return &HWConfig{ CpuCount: 1, + CoreCount: 1, MemorySize: 512, Sound: true, @@ -26,6 +27,10 @@ func TestHWConfigPrepare(t *testing.T) { t.Errorf("bad cpu count: %d", c.CpuCount) } + if c.CoreCount < 0 { + t.Errorf("bad core count: %d", c.CoreCount) + } + if c.MemorySize < 0 { t.Errorf("bad memory size: %d", c.MemorySize) } diff --git a/builder/vmware/iso/step_create_vmx.go b/builder/vmware/iso/step_create_vmx.go index ba9c273b6..3e95a13e8 100644 --- a/builder/vmware/iso/step_create_vmx.go +++ b/builder/vmware/iso/step_create_vmx.go @@ -423,12 +423,19 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist s.tempDir = vmxDir } - /// Now to handle options that will modify the template + /// Now to handle options that will modify the template without using "vmxTemplateData" vmxData := vmwcommon.ParseVMX(vmxContents) + + // If no cpus were specified, then remove the entry to use the default if vmxData["numvcpus"] == "" { delete(vmxData, "numvcpus") } + // If some number of cores were specified, then update "cpuid.coresPerSocket" with the requested value + if config.HWConfig.CoreCount > 0 { + vmxData["cpuid.corespersocket"] = strconv.Itoa(config.HWConfig.CoreCount) + } + /// Write the vmxData to the vmxPath vmxPath := filepath.Join(vmxDir, config.VMName+".vmx") if err := vmwcommon.WriteVMX(vmxPath, vmxData); err != nil { diff --git a/command/build_test.go b/command/build_test.go index 5e56d81f1..12f9709d2 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -37,6 +37,10 @@ func TestBuildOnlyFileCommaFlags(t *testing.T) { if fileExists("cherry.txt") { t.Error("Expected NOT to find cherry.txt") } + + if !fileExists("tomato.txt") { + t.Error("Expected to find tomato.txt") + } } func TestBuildStdin(t *testing.T) { @@ -104,7 +108,7 @@ func TestBuildExceptFileCommaFlags(t *testing.T) { } args := []string{ - "-except=chocolate,apple", + "-except=chocolate,vanilla", filepath.Join(testFixture("build-only"), "template.json"), } @@ -114,12 +118,12 @@ func TestBuildExceptFileCommaFlags(t *testing.T) { fatalCommand(t, c.Meta) } - for _, f := range []string{"chocolate.txt", "apple.txt", "peach.txt"} { + for _, f := range []string{"chocolate.txt", "vanilla.txt", "tomato.txt"} { if fileExists(f) { t.Errorf("Expected NOT to find %s", f) } } - for _, f := range []string{"vanilla.txt", "cherry.txt", "pear.txt"} { + for _, f := range []string{"apple.txt", "cherry.txt", "pear.txt", "peach.txt"} { if !fileExists(f) { t.Errorf("Expected to find %s", f) } @@ -169,4 +173,5 @@ func cleanup() { os.RemoveAll("apple.txt") os.RemoveAll("peach.txt") os.RemoveAll("pear.txt") + os.RemoveAll("tomato.txt") } diff --git a/command/test-fixtures/build-only/template.json b/command/test-fixtures/build-only/template.json index af09b6cbf..9ca20adca 100644 --- a/command/test-fixtures/build-only/template.json +++ b/command/test-fixtures/build-only/template.json @@ -38,6 +38,16 @@ "type": "shell-local", "inline": [ "touch pear.txt" ] } + ], + [ + { + "only": [ + "vanilla" + ], + "name": "tomato", + "type": "shell-local", + "inline": [ "touch tomato.txt" ] + } ] ] } \ No newline at end of file diff --git a/go.sum b/go.sum index 089c0099c..f6890eb5e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1 h1:RMTyvS5bjvSWiUcfqfr/E2pxHEMrALvU+E12n6biymg= github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1/go.mod h1:61apmbkVJH4kg+38ftT+/l0XxdUCVnHggqcOTqZRSEE= @@ -80,7 +81,7 @@ github.com/digitalocean/godo v0.0.0-20170407151542-4c04abe183f4 h1:34XBbvedApvUM github.com/digitalocean/godo v0.0.0-20170407151542-4c04abe183f4/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dnaeon/go-vcr v1.0.0 h1:1QZ+ahihvRvppcJnFvuoHAdnZTf1PqKjO4Ftr1cfQTo= github.com/dnaeon/go-vcr v1.0.0/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5 h1:V/WghsgVPZl+92drOvPEwuZdHskJmrnD83V1msaV/Jc= +github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5 h1:DwY2bFs8p+xf2WaQewx2hnGdjYR5K4UAaxcNPyKkTek= github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -140,7 +141,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI= github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:1yOKgt0XYKUg1HOKunGOSt2ocU4bxLCjmIHt0vRtVHM= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= @@ -169,7 +170,7 @@ github.com/hashicorp/go-plugin v0.0.0-20181030172320-54b6ff97d818 h1:wA1XRGBHMdp github.com/hashicorp/go-plugin v0.0.0-20181030172320-54b6ff97d818/go.mod h1:Ft7ju2vWzhO0ETMKUVo12XmXmII6eSUS4rsPTkY/siA= github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 h1:qCv4319q2q7XKn0MQbi8p37hsJ+9Xo8e6yojA73JVxk= github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= -github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 h1:9HVkPxOpo+yO93Ah4yrO67d/qh0fbLLWbKqhYjyHq9A= +github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 h1:VBj0QYQ0u2MCJzBfeYXGexnAl17GsH1yidnoxCqqD9E= github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -357,22 +358,27 @@ github.com/vmware/govmomi v0.0.0-20170707011325-c2105a174311 h1:s5pyxd5S6wRs2WpE github.com/vmware/govmomi v0.0.0-20170707011325-c2105a174311/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xanzy/go-cloudstack v2.1.4+incompatible h1:5c72sRFakVv8wH/HsQFg+xr37CmNQU2UbJfaBjW5f0c= github.com/xanzy/go-cloudstack v2.1.4+incompatible/go.mod h1:s3eL3z5pNXF5FVybcT+LIVdId8pYn709yv6v5mrkrQE= +golang.org/x/crypto v0.0.0-20180322175230-88942b9c40a4 h1:AJCW0rhPjFKEAoValWpqnRKxX8YV0Xvqfw+dOexCTPc= golang.org/x/crypto v0.0.0-20180322175230-88942b9c40a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/api v0.0.0-20180818000503-e21acd801f91 h1:MgYYgjaWMS2qQiDwCznfbqNmEOdSULlvjCvSCvIe/Wo= google.golang.org/api v0.0.0-20180818000503-e21acd801f91/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -407,7 +413,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/vmihailenco/msgpack.v2 v2.9.1 h1:kb0VV7NuIojvRfzwslQeP3yArBqJHW9tOl4t38VS1jM= gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:y0IMTfclpMdsdIbr6uwmJn5/WZ7vFuObxDMdrylFM3A= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/packer/core.go b/packer/core.go index feec80d24..a059f90c9 100644 --- a/packer/core.go +++ b/packer/core.go @@ -180,13 +180,18 @@ func (c *Core) Build(n string) (Build, error) { for _, rawPs := range c.Template.PostProcessors { current := make([]coreBuildPostProcessor, 0, len(rawPs)) for _, rawP := range rawPs { - // If we skip, ignore - rawP.OnlyExcept.Except = append(rawP.OnlyExcept.Except, c.except...) - if rawP.OnlyExcept.Skip(rawName) { + if rawP.Skip(rawName) { continue } - if rawP.OnlyExcept.Skip(rawP.Name) { - break + // -except skips post-processor & build + foundExcept := false + for _, except := range c.except { + if except == rawP.Name { + foundExcept = true + } + } + if foundExcept { + continue } // Get the post-processor diff --git a/post-processor/googlecompute-export/post-processor.go b/post-processor/googlecompute-export/post-processor.go index eb1fc786f..7631402a3 100644 --- a/post-processor/googlecompute-export/post-processor.go +++ b/post-processor/googlecompute-export/post-processor.go @@ -15,10 +15,19 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` - Paths []string `mapstructure:"paths"` - KeepOriginalImage bool `mapstructure:"keep_input_artifact"` + AccountFile string `mapstructure:"account_file"` - ctx interpolate.Context + DiskSizeGb int64 `mapstructure:"disk_size"` + DiskType string `mapstructure:"disk_type"` + KeepOriginalImage bool `mapstructure:"keep_input_artifact"` + MachineType string `mapstructure:"machine_type"` + Network string `mapstructure:"network"` + Paths []string `mapstructure:"paths"` + Subnetwork string `mapstructure:"subnetwork"` + Zone string `mapstructure:"zone"` + + Account googlecompute.AccountFile + ctx interpolate.Context } type PostProcessor struct { @@ -35,12 +44,38 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return err } + 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" + } + + if len(errs.Errors) > 0 { + return errs + } + return nil } func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { - ui.Say("Starting googlecompute-export...") - ui.Say(fmt.Sprintf("Exporting image to destinations: %v", p.config.Paths)) if artifact.BuilderId() != googlecompute.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only export from Google Compute Engine builder artifacts.", @@ -48,79 +83,90 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return nil, p.config.KeepOriginalImage, err } - result := &Artifact{paths: p.config.Paths} + builderAccountFile := artifact.State("AccountFilePath").(string) + builderImageName := artifact.State("ImageName").(string) + builderProjectId := artifact.State("ProjectId").(string) + builderZone := artifact.State("BuildZone").(string) - if len(p.config.Paths) > 0 { - accountKeyFilePath := artifact.State("AccountFilePath").(string) - imageName := artifact.State("ImageName").(string) - imageSizeGb := artifact.State("ImageSizeGb").(int64) - projectId := artifact.State("ProjectId").(string) - zone := artifact.State("BuildZone").(string) + ui.Say(fmt.Sprintf("Exporting image %v to destination: %v", builderImageName, p.config.Paths)) - // Set up instance configuration. - instanceName := fmt.Sprintf("%s-exporter", artifact.Id()) - metadata := map[string]string{ - "image_name": imageName, - "name": instanceName, - "paths": strings.Join(p.config.Paths, " "), - "startup-script": StartupScript, - "zone": zone, - } - exporterConfig := googlecompute.Config{ - InstanceName: instanceName, - SourceImageProjectId: "debian-cloud", - SourceImage: "debian-8-jessie-v20160629", - DiskName: instanceName, - DiskSizeGb: imageSizeGb + 10, - DiskType: "pd-standard", - Metadata: metadata, - MachineType: "n1-standard-4", - Zone: zone, - Network: "default", - RawStateTimeout: "5m", - Scopes: []string{ - "https://www.googleapis.com/auth/userinfo.email", - "https://www.googleapis.com/auth/compute", - "https://www.googleapis.com/auth/devstorage.full_control", - }, - } - exporterConfig.CalcTimeout() + if p.config.Zone == "" { + p.config.Zone = builderZone + } - // Set up credentials and GCE driver. - if accountKeyFilePath != "" { - err := googlecompute.ProcessAccountFile(&exporterConfig.Account, accountKeyFilePath) - if err != nil { - return nil, p.config.KeepOriginalImage, err - } - } - driver, err := googlecompute.NewDriverGCE(ui, projectId, &exporterConfig.Account) + // Set up credentials for GCE driver. + if builderAccountFile != "" { + err := googlecompute.ProcessAccountFile(&p.config.Account, builderAccountFile) if err != nil { return nil, p.config.KeepOriginalImage, err } - - // 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) - p.runner.Run(state) } + if p.config.AccountFile != "" { + err := googlecompute.ProcessAccountFile(&p.config.Account, p.config.AccountFile) + if err != nil { + return nil, p.config.KeepOriginalImage, err + } + } + + // 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, + RawStateTimeout: "5m", + 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", + }, + } + exporterConfig.CalcTimeout() + + driver, err := googlecompute.NewDriverGCE(ui, builderProjectId, &p.config.Account) + if err != nil { + return nil, p.config.KeepOriginalImage, err + } + + // 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) + p.runner.Run(state) + + result := &Artifact{paths: p.config.Paths} return result, p.config.KeepOriginalImage, nil } diff --git a/post-processor/googlecompute-export/startup.go b/post-processor/googlecompute-export/startup.go index abd9f752f..779c97405 100644 --- a/post-processor/googlecompute-export/startup.go +++ b/post-processor/googlecompute-export/startup.go @@ -1,6 +1,6 @@ package googlecomputeexport -var StartupScript string = `#!/bin/sh +var StartupScript string = `#!/bin/bash GetMetadata () { echo "$(curl -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/$1 2> /dev/null)" @@ -8,11 +8,11 @@ GetMetadata () { IMAGENAME=$(GetMetadata image_name) NAME=$(GetMetadata name) DISKNAME=${NAME}-toexport -PATHS=$(GetMetadata paths) +PATHS=($(GetMetadata paths)) ZONE=$(GetMetadata zone) Exit () { - for i in ${PATHS}; do + for i in ${PATHS[@]}; do LOGDEST="${i}.exporter.log" echo "Uploading exporter log to ${LOGDEST}..." gsutil -h "Content-Type:text/plain" cp /var/log/daemon.log ${LOGDEST} @@ -40,17 +40,15 @@ if ! gcloud compute instances attach-disk ${NAME} --disk ${DISKNAME} --device-na Exit 1 fi -echo "Dumping disk..." -if ! dd if=/dev/disk/by-id/google-toexport of=disk.raw bs=4096 conv=sparse; then - echo "Failed to dump disk to image." +echo "GCEExport: Running export tool." +gce_export -gcs_path "${PATHS[0]}" -disk /dev/disk/by-id/google-toexport -y +if [ $? -ne 0 ]; then + echo "ExportFailed: Failed to export disk source to ${PATHS[0]}." Exit 1 fi -echo "Compressing and tar'ing disk image..." -if ! tar -czf root.tar.gz disk.raw; then - echo "Failed to tar disk image." - Exit 1 -fi +echo "ExportSuccess" +sync echo "Detaching disk..." if ! gcloud compute instances detach-disk ${NAME} --disk ${DISKNAME} --zone ${ZONE}; then @@ -64,10 +62,10 @@ if ! gcloud compute disks delete ${DISKNAME} --zone ${ZONE}; then FAIL=1 fi -for i in ${PATHS}; do - echo "Uploading tar'ed disk image to ${i}..." - if ! gsutil -o GSUtil:parallel_composite_upload_threshold=100M cp root.tar.gz ${i}; then - echo "Failed to upload image to ${i}." +for i in ${PATHS[@]:1}; do + echo "Copying archive image to ${i}..." + if ! gsutil -o GSUtil:parallel_composite_upload_threshold=100M cp ${PATHS[0]} ${i}; then + echo "Failed to copy image to ${i}." FAIL=1 fi done diff --git a/post-processor/googlecompute-import/post-processor.go b/post-processor/googlecompute-import/post-processor.go index 6f44b1ce9..4dfb1fee9 100644 --- a/post-processor/googlecompute-import/post-processor.go +++ b/post-processor/googlecompute-import/post-processor.go @@ -13,13 +13,9 @@ import ( "github.com/hashicorp/packer/builder/googlecompute" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" - "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/post-processor/compress" "github.com/hashicorp/packer/template/interpolate" - - "golang.org/x/oauth2" - "golang.org/x/oauth2/jwt" ) type Config struct { @@ -38,12 +34,12 @@ type Config struct { KeepOriginalImage bool `mapstructure:"keep_input_artifact"` SkipClean bool `mapstructure:"skip_clean"` - ctx interpolate.Context + Account googlecompute.AccountFile + ctx interpolate.Context } type PostProcessor struct { config Config - runner multistep.Runner } func (p *PostProcessor) Configure(raws ...interface{}) error { @@ -60,24 +56,29 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return err } + errs := new(packer.MultiError) + // Set defaults if p.config.GCSObjectName == "" { p.config.GCSObjectName = "packer-import-{{timestamp}}.tar.gz" } - errs := new(packer.MultiError) - // Check and render gcs_object_name if err = interpolate.Validate(p.config.GCSObjectName, &p.config.ctx); err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Error parsing gcs_object_name template: %s", err)) } + if p.config.AccountFile != "" { + if err := googlecompute.ProcessAccountFile(&p.config.Account, p.config.AccountFile); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + } + templates := map[string]*string{ - "bucket": &p.config.Bucket, - "image_name": &p.config.ImageName, - "project_id": &p.config.ProjectId, - "account_file": &p.config.AccountFile, + "bucket": &p.config.Bucket, + "image_name": &p.config.ImageName, + "project_id": &p.config.ProjectId, } for key, ptr := range templates { if *ptr == "" { @@ -94,7 +95,10 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { - var err error + client, err := googlecompute.NewClientGCE(&p.config.Account) + if err != nil { + return nil, false, err + } if artifact.BuilderId() != compress.BuilderId { err = fmt.Errorf( @@ -108,18 +112,18 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return nil, false, fmt.Errorf("Error rendering gcs_object_name template: %s", err) } - rawImageGcsPath, err := UploadToBucket(p.config.AccountFile, ui, artifact, p.config.Bucket, p.config.GCSObjectName) + rawImageGcsPath, err := UploadToBucket(client, ui, artifact, p.config.Bucket, p.config.GCSObjectName) if err != nil { return nil, p.config.KeepOriginalImage, err } - gceImageArtifact, err := CreateGceImage(p.config.AccountFile, ui, p.config.ProjectId, rawImageGcsPath, p.config.ImageName, p.config.ImageDescription, p.config.ImageFamily, p.config.ImageLabels, p.config.ImageGuestOsFeatures) + gceImageArtifact, err := CreateGceImage(client, ui, p.config.ProjectId, rawImageGcsPath, p.config.ImageName, p.config.ImageDescription, p.config.ImageFamily, p.config.ImageLabels, p.config.ImageGuestOsFeatures) if err != nil { return nil, p.config.KeepOriginalImage, err } if !p.config.SkipClean { - err = DeleteFromBucket(p.config.AccountFile, ui, p.config.Bucket, p.config.GCSObjectName) + err = DeleteFromBucket(client, ui, p.config.Bucket, p.config.GCSObjectName) if err != nil { return nil, p.config.KeepOriginalImage, err } @@ -128,24 +132,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return gceImageArtifact, p.config.KeepOriginalImage, nil } -func UploadToBucket(accountFile string, ui packer.Ui, artifact packer.Artifact, bucket string, gcsObjectName string) (string, error) { - var client *http.Client - var account googlecompute.AccountFile - - err := googlecompute.ProcessAccountFile(&account, accountFile) - if err != nil { - return "", err - } - - var DriverScopes = []string{"https://www.googleapis.com/auth/devstorage.full_control"} - conf := jwt.Config{ - Email: account.ClientEmail, - PrivateKey: []byte(account.PrivateKey), - Scopes: DriverScopes, - TokenURL: "https://accounts.google.com/o/oauth2/token", - } - - client = conf.Client(oauth2.NoContext) +func UploadToBucket(client *http.Client, ui packer.Ui, artifact packer.Artifact, bucket string, gcsObjectName string) (string, error) { service, err := storage.New(client) if err != nil { return "", err @@ -162,7 +149,7 @@ func UploadToBucket(accountFile string, ui packer.Ui, artifact packer.Artifact, } if source == "" { - return "", fmt.Errorf("No tar.gz file found in list of articats") + return "", fmt.Errorf("No tar.gz file found in list of artifacts") } artifactFile, err := os.Open(source) @@ -178,28 +165,10 @@ func UploadToBucket(accountFile string, ui packer.Ui, artifact packer.Artifact, return "", err } - return "https://storage.googleapis.com/" + bucket + "/" + gcsObjectName, nil + return storageObject.SelfLink, nil } -func CreateGceImage(accountFile string, ui packer.Ui, project string, rawImageURL string, imageName string, imageDescription string, imageFamily string, imageLabels map[string]string, imageGuestOsFeatures []string) (packer.Artifact, error) { - var client *http.Client - var account googlecompute.AccountFile - - err := googlecompute.ProcessAccountFile(&account, accountFile) - if err != nil { - return nil, err - } - - var DriverScopes = []string{"https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control"} - conf := jwt.Config{ - Email: account.ClientEmail, - PrivateKey: []byte(account.PrivateKey), - Scopes: DriverScopes, - TokenURL: "https://accounts.google.com/o/oauth2/token", - } - - client = conf.Client(oauth2.NoContext) - +func CreateGceImage(client *http.Client, ui packer.Ui, project string, rawImageURL string, imageName string, imageDescription string, imageFamily string, imageLabels map[string]string, imageGuestOsFeatures []string) (packer.Artifact, error) { service, err := compute.New(client) if err != nil { return nil, err @@ -253,24 +222,7 @@ func CreateGceImage(accountFile string, ui packer.Ui, project string, rawImageUR return &Artifact{paths: []string{op.TargetLink}}, nil } -func DeleteFromBucket(accountFile string, ui packer.Ui, bucket string, gcsObjectName string) error { - var client *http.Client - var account googlecompute.AccountFile - - err := googlecompute.ProcessAccountFile(&account, accountFile) - if err != nil { - return err - } - - var DriverScopes = []string{"https://www.googleapis.com/auth/devstorage.full_control"} - conf := jwt.Config{ - Email: account.ClientEmail, - PrivateKey: []byte(account.PrivateKey), - Scopes: DriverScopes, - TokenURL: "https://accounts.google.com/o/oauth2/token", - } - - client = conf.Client(oauth2.NoContext) +func DeleteFromBucket(client *http.Client, ui packer.Ui, bucket string, gcsObjectName string) error { service, err := storage.New(client) if err != nil { return err diff --git a/post-processor/manifest/artifact.go b/post-processor/manifest/artifact.go index 50ecc15a0..59d6110eb 100644 --- a/post-processor/manifest/artifact.go +++ b/post-processor/manifest/artifact.go @@ -10,12 +10,13 @@ type ArtifactFile struct { } type Artifact struct { - BuildName string `json:"name"` - BuilderType string `json:"builder_type"` - BuildTime int64 `json:"build_time"` - ArtifactFiles []ArtifactFile `json:"files"` - ArtifactId string `json:"artifact_id"` - PackerRunUUID string `json:"packer_run_uuid"` + BuildName string `json:"name"` + BuilderType string `json:"builder_type"` + BuildTime int64 `json:"build_time"` + ArtifactFiles []ArtifactFile `json:"files"` + ArtifactId string `json:"artifact_id"` + PackerRunUUID string `json:"packer_run_uuid"` + CustomData map[string]string `json:"custom_data"` } func (a *Artifact) BuilderId() string { diff --git a/post-processor/manifest/post-processor.go b/post-processor/manifest/post-processor.go index f5807dbb2..8833f2abe 100644 --- a/post-processor/manifest/post-processor.go +++ b/post-processor/manifest/post-processor.go @@ -18,8 +18,9 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` - OutputPath string `mapstructure:"output"` - StripPath bool `mapstructure:"strip_path"` + OutputPath string `mapstructure:"output"` + StripPath bool `mapstructure:"strip_path"` + CustomData map[string]string `mapstructure:"custom_data"` ctx interpolate.Context } @@ -75,6 +76,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packe artifact.ArtifactFiles = append(artifact.ArtifactFiles, af) } artifact.ArtifactId = source.Id() + artifact.CustomData = p.config.CustomData artifact.BuilderType = p.config.PackerBuilderType artifact.BuildName = p.config.PackerBuildName artifact.BuildTime = time.Now().Unix() diff --git a/scripts/build.sh b/scripts/build.sh index 4f55b9893..5e24244d7 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -5,63 +5,109 @@ ALL_XC_ARCH="386 amd64 arm arm64 ppc64le" ALL_XC_OS="linux darwin windows freebsd openbsd solaris" +# Exit immediately if a command fails set -e +# Validates that a necessary tool is on the PATH +function validateToolPresence +{ + local TOOLNAME=$1 + which ${TOOLNAME} >/dev/null || echo "${TOOLNAME} is not on the path. Exiting..." + exit 1 +} + +# Validates that all used tools are present; exits when any is not found +function validatePreconditions +{ + echo "==> Checking for necessary tools..." + validateToolPresence realpath + validateToolPresence dirname + validateToolPresence tr + validateToolPresence find +} + # Get the parent directory of where this script is. -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done -DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" +# NOTE: I'm unsure why you don't just use realpath like below +function enterPackerSourceDir +{ + echo "==> Entering Packer source dir..." + local BUILD_SCRIPT_PATH="${BASH_SOURCE[0]}" + SOURCEDIR=$(dirname $(dirname $(realpath "${BUILD_SCRIPT_PATH}"))) + cd ${SOURCEDIR} +} -# Change into that directory -cd $DIR +function ensureOutputStructure { + echo "==> Ensuring output directories are present..." + mkdir -p bin/ + mkdir -p pkg/ +} -# Delete the old dir -echo "==> Removing old directory..." -rm -f bin/* -rm -rf pkg/* -mkdir -p bin/ +function cleanOutputDirs { + echo "==> Removing old builds..." + rm -f bin/* + rm -fr pkg/* +} -# helpers for Cygwin-hosted builds -: ${OSTYPE:=`uname`} +function lowerCaseOSType { + local OS_TYPE=${OSTYPE:=`uname`} + echo "${OS_TYPE}" | tr "[:upper:]" "[:lower:]" +} -case $OSTYPE in - MINGW*|MSYS*|cygwin|CYGWIN*) - # cygwin only translates ';' to ':' on select environment variables - PATHSEP=';' - ;; - *) PATHSEP=':' -esac - -function convert_path() { - local flag - [ "${1:0:1}" = '-' ] && { flag="$1"; shift; } - - [ -n "$1" ] || return 0 - case ${OSTYPE:-`uname`} in - cygwin|CYGWIN*) - cygpath $flag -- "$1" +# Returns the OS appropriate path separator +function getPathSeparator { + # helpers for Cygwin-hosted builds + case "$(lowerCaseOSType)" in + mingw*|msys*|cygwin*) + # cygwin only translates ';' to ':' on select environment variables + echo ';' ;; - *) echo "$1" + *) echo ':' esac } -# XXX works in MINGW? -which go &>/dev/null || PATH+=":`convert_path "${GOROOT:?}"`/bin" +function convertPathOnCygwin() { + local flag + local somePath + if [ "${1:0:1}" = '-' ]; then + flag=$1 + somePath=$2 + else + somePath=$1 + fi -OLDIFS="$IFS" + [ -n "${somePath}" ] || return 0 + case "$(lowerCaseOSType)" in + cygwin*) + cygpath ${flag} -- "${somePath}" + ;; + *) echo "${somePath}" + esac +} + +enterPackerSourceDir +ensureOutputStructure +cleanOutputDirs + +PATHSEP=$(getPathSeparator) + +# XXX works in MINGW? +# FIXME: What if go is not in the PATH and GOROOT isn't set? +which go &>/dev/null || PATH+=":`convertPathOnCygwin "${GOROOT:?}"`/bin" + +OLDIFS="${IFS}" # make sure GOPATH is consistent - Windows binaries can't handle Cygwin-style paths -IFS="$PATHSEP" +IFS="${PATHSEP}" for d in ${GOPATH:-$(go env GOPATH)}; do - _GOPATH+="${_GOPATH:+$PATHSEP}$(convert_path --windows "$d")" + _GOPATH+="${_GOPATH:+${PATHSEP}}$(convertPathOnCygwin --windows "${d}")" done GOPATH="$_GOPATH" # locate 'gox' and traverse GOPATH if needed which "${GOX:=gox}" &>/dev/null || { - for d in $GOPATH; do - GOX="$(convert_path --unix "$d")/bin/gox" - [ -x "$GOX" ] && break || unset GOX + for d in ${GOPATH}; do + GOX="$(convertPathOnCygwin --unix "${d}")/bin/gox" + [ -x "${GOX}" ] && break || unset GOX done } IFS="$OLDIFS" @@ -86,17 +132,18 @@ ${GOX:?command not found} \ set -e # trim GOPATH to first element -IFS="$PATHSEP" -MAIN_GOPATH=($GOPATH) -MAIN_GOPATH="$(convert_path --unix "$MAIN_GOPATH")" -IFS=$OLDIFS +IFS="${PATHSEP}" +# FIXME: How do you know that the first path of GOPATH is the main GOPATH? Or is the main GOPATH meant to be the first path in GOPATH? +MAIN_GOPATH=(${GOPATH}) +MAIN_GOPATH="$(convertPathOnCygwin --unix "${MAIN_GOPATH[0]}")" +IFS="${OLDIFS}" # Copy our OS/Arch to the bin/ directory echo "==> Copying binaries for this platform..." -DEV_PLATFORM="./pkg/$(go env GOOS)_$(go env GOARCH)" +DEV_PLATFORM="./pkg/${XC_OS}_${XC_ARCH}" for F in $(find ${DEV_PLATFORM} -mindepth 1 -maxdepth 1 -type f 2>/dev/null); do cp -v ${F} bin/ - cp -v ${F} ${MAIN_GOPATH}/bin/ + cp -v ${F} "${MAIN_GOPATH}/bin/" done # Done! diff --git a/website/source/docs/builders/hyperv-iso.html.md.erb b/website/source/docs/builders/hyperv-iso.html.md.erb index 6d989713a..0c2e6aa9f 100644 --- a/website/source/docs/builders/hyperv-iso.html.md.erb +++ b/website/source/docs/builders/hyperv-iso.html.md.erb @@ -94,7 +94,7 @@ builder. Packer to wait for 1 minute 30 seconds before typing the boot command. The default duration is "10s" (10 seconds). -- `configuration_version` - This allows you to set the vm version when +- `configuration_version` (string) - This allows you to set the vm version when calling New-VM to generate the vm. - `cpu` (number) - The number of CPUs the virtual machine should use. If diff --git a/website/source/docs/builders/hyperv-vmcx.html.md.erb b/website/source/docs/builders/hyperv-vmcx.html.md.erb index de5cdd176..af549bb94 100644 --- a/website/source/docs/builders/hyperv-vmcx.html.md.erb +++ b/website/source/docs/builders/hyperv-vmcx.html.md.erb @@ -116,7 +116,7 @@ builder. This setting only has an effect if using `clone_from_vm_name` and is ignored otherwise. -- `copy_in_compare` - (bool) When cloning a vm to build from, we run a powershell +- `copy_in_compare` (boolean) - When cloning a vm to build from, we run a powershell Compare-VM command, which, depending on your version of Windows, may need the "Copy" flag to be set to true or false. Defaults to "false". Command: @@ -125,7 +125,7 @@ builder. Where $copy is replaced with either true or false depending on the value of "copy_in_compare". -- `configuration_version` - This allows you to set the vm version when +- `configuration_version` (string) - This allows you to set the vm version when calling New-VM to generate the vm. - `cpu` (number) - The number of CPUs the virtual machine should use. If diff --git a/website/source/docs/builders/tencentcloud-cvm.html.md b/website/source/docs/builders/tencentcloud-cvm.html.md index 45ae31ce3..544dee29e 100644 --- a/website/source/docs/builders/tencentcloud-cvm.html.md +++ b/website/source/docs/builders/tencentcloud-cvm.html.md @@ -3,8 +3,8 @@ description: | The `tencentcloud-cvm` Packer builder plugin provide the capability to build customized images based on an existing base images. layout: docs -page_title: Tencentcloud Image Builder -sidebar_current: 'docs-builders-tencentcloud-ecs' +page_title: 'Tencentcloud Image Builder' +sidebar_current: 'docs-builders-tencentcloud-cvm' --- # Tencentcloud Image Builder @@ -88,16 +88,16 @@ builder. - LOCAL_BASIC: 50 - Other: 50 ~ 1000 (need whitelist if > 50) -- `vpc_id` - Specify vpc your cvm will be launched by. +- `vpc_id` (string) - Specify vpc your cvm will be launched by. -- `vpc_name` - Specify vpc name you will create. if `vpc_id` is not set, packer will +- `vpc_name` (string) - Specify vpc name you will create. if `vpc_id` is not set, packer will create a vpc for you named this parameter. - `cidr_block` (boolean) - Specify cider block of the vpc you will create if `vpc_id` not set -- `subnet_id` - Specify subnet your cvm will be launched by. +- `subnet_id` (string) - Specify subnet your cvm will be launched by. -- 'subnet_name' - Specify subnet name you will create. if `subnet_id` is not set, packer will +- `subnet_name` (string) - Specify subnet name you will create. if `subnet_id` is not set, packer will create a subnet for you named this parameter. - `subnect_cidr_block` (boolean) - Specify cider block of the subnet you will create if @@ -106,15 +106,15 @@ builder. - `internet_max_bandwidth_out` (number) - Max bandwidth out your cvm will be launched by(in MB). values can be set between 1 ~ 100. -- `security_group_id` - Specify security group your cvm will be launched by. +- `security_group_id` (string) - Specify security group your cvm will be launched by. -- `security_group_name` - Specify security name you will create if `security_group_id` not set. +- `security_group_name` (string) - Specify security name you will create if `security_group_id` not set. -- `user_data` - userdata. +- `user_data` (string) - userdata. -- `user_data_file` - userdata file. +- `user_data_file` (string) - userdata file. -- `host_name` - host name. +- `host_name` (string) - host name. ## Basic Example diff --git a/website/source/docs/builders/vmware-iso.html.md.erb b/website/source/docs/builders/vmware-iso.html.md.erb index 12d0d77cc..0a2411d79 100644 --- a/website/source/docs/builders/vmware-iso.html.md.erb +++ b/website/source/docs/builders/vmware-iso.html.md.erb @@ -100,6 +100,9 @@ builder. - `cpus` (number) - The number of cpus to use when building the VM. +- `cores` (number) - The number of cores per socket to use when building the VM. + This corresponds to the `cpuid.coresPerSocket` option in the .vmx file. + - `cdrom_adapter_type` (string) - The adapter type (or bus) that will be used by the cdrom device. This is chosen by default based on the disk adapter type. VMware tends to lean towards `ide` for the cdrom device unless diff --git a/website/source/docs/post-processors/docker-import.html.md b/website/source/docs/post-processors/docker-import.html.md index 1d3e413d7..8802a18e7 100644 --- a/website/source/docs/post-processors/docker-import.html.md +++ b/website/source/docs/post-processors/docker-import.html.md @@ -29,11 +29,11 @@ is optional. - `repository` (string) - The repository of the imported image. +### Optional: + - `tag` (string) - The tag for the imported image. By default this is not set. -### Optional: - - `changes` (array of strings) - Dockerfile instructions to add to the commit. Example of instructions are `CMD`, `ENTRYPOINT`, `ENV`, and `EXPOSE`. Example: `[ "USER ubuntu", "WORKDIR /app", "EXPOSE 8080" ]` diff --git a/website/source/docs/post-processors/googlecompute-export.html.md b/website/source/docs/post-processors/googlecompute-export.html.md index d3e13874d..98061cddf 100644 --- a/website/source/docs/post-processors/googlecompute-export.html.md +++ b/website/source/docs/post-processors/googlecompute-export.html.md @@ -34,9 +34,39 @@ permissions to the GCS `paths`. ### Optional +- `account_file` (string) - The JSON file containing your account + credentials. If specified, this take precedence over `googlecompute` + builder authentication method. + +- `disk_size` (number) - The size of the export instances disk, this disk + is unused for the export but a larger size increase `pd-ssd` read speed. + This defaults to `200`, which is 200GB. + +- `disk_type` (string) - Type of disk used to back export instance, like + `pd-ssd` or `pd-standard`. Defaults to `pd-ssd`. + - `keep_input_artifact` (boolean) - If true, do not delete the Google Compute Engine (GCE) image being exported. +- `machine_type` (string) - The export instance machine type. Defaults + to `"n1-highcpu-4"`. + +- `network` (string) - The Google Compute network id or URL to use for the + export instance. Defaults to `"default"`. If the value is not a URL, it + will be interpolated to + `projects/((network_project_id))/global/networks/((network))`. This value + is not required if a `subnet` is specified. + +- `subnetwork` (string) - The Google Compute subnetwork id or URL to use for + the export instance. Only required if the `network` has been created with + custom subnetting. Note, the region of the subnetwork must match the + `zone` in which the VM is launched. If the value is not a URL, + it will be interpolated to + `projects/((network_project_id))/regions/((region))/subnetworks/((subnetwork))` + +- `zone` (string) - The zone in which to launch the export instance. Defaults + to `googlecompute` builder zone. Example: `"us-central1-a"` + ## Basic Example The following example builds a GCE image in the project, `my-project`, with an diff --git a/website/source/docs/post-processors/manifest.html.md b/website/source/docs/post-processors/manifest.html.md index 56127c54d..3bb9bef3b 100644 --- a/website/source/docs/post-processors/manifest.html.md +++ b/website/source/docs/post-processors/manifest.html.md @@ -38,11 +38,12 @@ post-processors such as Docker and Artifice. to `packer-manifest.json`. - `strip_path` (boolean) Write only filename without the path to the manifest file. This defaults to false. +- `custom_data` (map of strings) Arbitrary data to add to the manifest. ### Example Configuration You can simply add `{"type":"manifest"}` to your post-processor section. Below -is a more verbose example: +is a more complete example: ``` json { @@ -50,7 +51,10 @@ is a more verbose example: { "type": "manifest", "output": "manifest.json", - "strip_path": true + "strip_path": true, + "custom_data": { + "my_custom_data": "example" + } } ] } @@ -72,7 +76,10 @@ An example manifest file looks like: } ], "artifact_id": "Container", - "packer_run_uuid": "6d5d3185-fa95-44e1-8775-9e64fe2e2d8f" + "packer_run_uuid": "6d5d3185-fa95-44e1-8775-9e64fe2e2d8f", + "custom_data": { + "my_custom_data": "example" + } } ], "last_run_uuid": "6d5d3185-fa95-44e1-8775-9e64fe2e2d8f" @@ -114,7 +121,10 @@ The above manifest was generated with this packer.json: { "type": "manifest", "output": "manifest.json", - "strip_path": true + "strip_path": true, + "custom_data": { + "my_custom_data": "example" + } } ] } diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index 5a9f4436d..e0cf12c86 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -162,6 +162,9 @@ > Scaleway + > + Tencent Cloud + > Triton