Merge branch 'master' into 'ephemeral-ssh-key-pair-issue-7225'.
This commit is contained in:
commit
ea2a7c3fe9
|
@ -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 {
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
"type": "shell-local",
|
||||
"inline": [ "touch pear.txt" ]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"only": [
|
||||
"vanilla"
|
||||
],
|
||||
"name": "tomato",
|
||||
"type": "shell-local",
|
||||
"inline": [ "touch tomato.txt" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
14
go.sum
14
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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
133
scripts/build.sh
133
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!
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" ]`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -162,6 +162,9 @@
|
|||
<li<%= sidebar_current("docs-builders-scaleway") %>>
|
||||
<a href="/docs/builders/scaleway.html">Scaleway</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-builders-tencentcloud-cvm") %>>
|
||||
<a href="/docs/builders/tencentcloud-cvm.html">Tencent Cloud</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-builders-triton") %>>
|
||||
<a href="/docs/builders/triton.html">Triton</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue