github.com/marksheahan/packer@v0.10.2-0.20160613200515-1acb2d6645a0/builder/googlecompute/config.go (about) 1 package googlecompute 2 3 import ( 4 "errors" 5 "fmt" 6 "regexp" 7 "time" 8 9 "github.com/mitchellh/packer/common" 10 "github.com/mitchellh/packer/common/uuid" 11 "github.com/mitchellh/packer/helper/communicator" 12 "github.com/mitchellh/packer/helper/config" 13 "github.com/mitchellh/packer/packer" 14 "github.com/mitchellh/packer/template/interpolate" 15 ) 16 17 var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`) 18 19 // Config is the configuration structure for the GCE builder. It stores 20 // both the publicly settable state as well as the privately generated 21 // state of the config object. 22 type Config struct { 23 common.PackerConfig `mapstructure:",squash"` 24 Comm communicator.Config `mapstructure:",squash"` 25 26 AccountFile string `mapstructure:"account_file"` 27 ProjectId string `mapstructure:"project_id"` 28 29 DiskName string `mapstructure:"disk_name"` 30 DiskSizeGb int64 `mapstructure:"disk_size"` 31 DiskType string `mapstructure:"disk_type"` 32 ImageName string `mapstructure:"image_name"` 33 ImageDescription string `mapstructure:"image_description"` 34 ImageFamily string `mapstructure:"image_family"` 35 InstanceName string `mapstructure:"instance_name"` 36 MachineType string `mapstructure:"machine_type"` 37 Metadata map[string]string `mapstructure:"metadata"` 38 Network string `mapstructure:"network"` 39 Subnetwork string `mapstructure:"subnetwork"` 40 Address string `mapstructure:"address"` 41 Preemptible bool `mapstructure:"preemptible"` 42 SourceImage string `mapstructure:"source_image"` 43 SourceImageProjectId string `mapstructure:"source_image_project_id"` 44 RawStateTimeout string `mapstructure:"state_timeout"` 45 Tags []string `mapstructure:"tags"` 46 UseInternalIP bool `mapstructure:"use_internal_ip"` 47 Region string `mapstructure:"region"` 48 Zone string `mapstructure:"zone"` 49 50 account accountFile 51 privateKeyBytes []byte 52 stateTimeout time.Duration 53 ctx interpolate.Context 54 } 55 56 func NewConfig(raws ...interface{}) (*Config, []string, error) { 57 c := new(Config) 58 err := config.Decode(c, &config.DecodeOpts{ 59 Interpolate: true, 60 InterpolateContext: &c.ctx, 61 InterpolateFilter: &interpolate.RenderFilter{ 62 Exclude: []string{ 63 "run_command", 64 }, 65 }, 66 }, raws...) 67 if err != nil { 68 return nil, nil, err 69 } 70 71 var errs *packer.MultiError 72 73 // Set defaults. 74 if c.Network == "" { 75 c.Network = "default" 76 } 77 78 if c.DiskSizeGb == 0 { 79 c.DiskSizeGb = 10 80 } 81 82 if c.DiskType == "" { 83 c.DiskType = "pd-standard" 84 } 85 86 if c.ImageDescription == "" { 87 c.ImageDescription = "Created by Packer" 88 } 89 90 if c.ImageName == "" { 91 img, err := interpolate.Render("packer-{{timestamp}}", nil) 92 if err != nil { 93 errs = packer.MultiErrorAppend(errs, 94 fmt.Errorf("Unable to parse image name: %s ", err)) 95 } else { 96 c.ImageName = img 97 } 98 } 99 100 if len(c.ImageFamily) > 63 { 101 errs = packer.MultiErrorAppend(errs, 102 errors.New("Invalid image family: Must not be longer than 63 characters")) 103 } 104 105 if c.ImageFamily != "" { 106 if !reImageFamily.MatchString(c.ImageFamily) { 107 errs = packer.MultiErrorAppend(errs, 108 errors.New("Invalid image family: The first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash")) 109 } 110 111 } 112 113 if c.InstanceName == "" { 114 c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) 115 } 116 117 if c.DiskName == "" { 118 c.DiskName = c.InstanceName 119 } 120 121 if c.MachineType == "" { 122 c.MachineType = "n1-standard-1" 123 } 124 125 if c.RawStateTimeout == "" { 126 c.RawStateTimeout = "5m" 127 } 128 129 if c.Comm.SSHUsername == "" { 130 c.Comm.SSHUsername = "root" 131 } 132 133 if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { 134 errs = packer.MultiErrorAppend(errs, es...) 135 } 136 137 // Process required parameters. 138 if c.ProjectId == "" { 139 errs = packer.MultiErrorAppend( 140 errs, errors.New("a project_id must be specified")) 141 } 142 143 if c.SourceImage == "" { 144 errs = packer.MultiErrorAppend( 145 errs, errors.New("a source_image must be specified")) 146 } 147 148 if c.Zone == "" { 149 errs = packer.MultiErrorAppend( 150 errs, errors.New("a zone must be specified")) 151 } 152 if c.Region == "" && len(c.Zone) > 2 { 153 // get region from Zone 154 region := c.Zone[:len(c.Zone)-2] 155 c.Region = region 156 } 157 158 stateTimeout, err := time.ParseDuration(c.RawStateTimeout) 159 if err != nil { 160 errs = packer.MultiErrorAppend( 161 errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) 162 } 163 c.stateTimeout = stateTimeout 164 165 if c.AccountFile != "" { 166 if err := processAccountFile(&c.account, c.AccountFile); err != nil { 167 errs = packer.MultiErrorAppend(errs, err) 168 } 169 } 170 171 // Check for any errors. 172 if errs != nil && len(errs.Errors) > 0 { 173 return nil, nil, errs 174 } 175 176 return c, nil, nil 177 }