github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/digitalocean/config.go (about) 1 package digitalocean 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/hashicorp/packer/common" 10 "github.com/hashicorp/packer/common/uuid" 11 "github.com/hashicorp/packer/helper/communicator" 12 "github.com/hashicorp/packer/helper/config" 13 "github.com/hashicorp/packer/packer" 14 "github.com/hashicorp/packer/template/interpolate" 15 "github.com/mitchellh/mapstructure" 16 ) 17 18 type Config struct { 19 common.PackerConfig `mapstructure:",squash"` 20 Comm communicator.Config `mapstructure:",squash"` 21 22 APIToken string `mapstructure:"api_token"` 23 APIURL string `mapstructure:"api_url"` 24 25 Region string `mapstructure:"region"` 26 Size string `mapstructure:"size"` 27 Image string `mapstructure:"image"` 28 29 PrivateNetworking bool `mapstructure:"private_networking"` 30 Monitoring bool `mapstructure:"monitoring"` 31 IPv6 bool `mapstructure:"ipv6"` 32 SnapshotName string `mapstructure:"snapshot_name"` 33 SnapshotRegions []string `mapstructure:"snapshot_regions"` 34 StateTimeout time.Duration `mapstructure:"state_timeout"` 35 DropletName string `mapstructure:"droplet_name"` 36 UserData string `mapstructure:"user_data"` 37 UserDataFile string `mapstructure:"user_data_file"` 38 39 ctx interpolate.Context 40 } 41 42 func NewConfig(raws ...interface{}) (*Config, []string, error) { 43 c := new(Config) 44 45 var md mapstructure.Metadata 46 err := config.Decode(c, &config.DecodeOpts{ 47 Metadata: &md, 48 Interpolate: true, 49 InterpolateContext: &c.ctx, 50 InterpolateFilter: &interpolate.RenderFilter{ 51 Exclude: []string{ 52 "run_command", 53 }, 54 }, 55 }, raws...) 56 if err != nil { 57 return nil, nil, err 58 } 59 60 // Defaults 61 if c.APIToken == "" { 62 // Default to environment variable for api_token, if it exists 63 c.APIToken = os.Getenv("DIGITALOCEAN_API_TOKEN") 64 } 65 if c.APIURL == "" { 66 c.APIURL = os.Getenv("DIGITALOCEAN_API_URL") 67 } 68 if c.SnapshotName == "" { 69 def, err := interpolate.Render("packer-{{timestamp}}", nil) 70 if err != nil { 71 panic(err) 72 } 73 74 // Default to packer-{{ unix timestamp (utc) }} 75 c.SnapshotName = def 76 } 77 78 if c.DropletName == "" { 79 // Default to packer-[time-ordered-uuid] 80 c.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) 81 } 82 83 if c.StateTimeout == 0 { 84 // Default to 6 minute timeouts waiting for 85 // desired state. i.e waiting for droplet to become active 86 c.StateTimeout = 6 * time.Minute 87 } 88 89 var errs *packer.MultiError 90 if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { 91 errs = packer.MultiErrorAppend(errs, es...) 92 } 93 if c.APIToken == "" { 94 // Required configurations that will display errors if not set 95 errs = packer.MultiErrorAppend( 96 errs, errors.New("api_token for auth must be specified")) 97 } 98 99 if c.Region == "" { 100 errs = packer.MultiErrorAppend( 101 errs, errors.New("region is required")) 102 } 103 104 if c.Size == "" { 105 errs = packer.MultiErrorAppend( 106 errs, errors.New("size is required")) 107 } 108 109 if c.Image == "" { 110 errs = packer.MultiErrorAppend( 111 errs, errors.New("image is required")) 112 } 113 114 if c.UserData != "" && c.UserDataFile != "" { 115 errs = packer.MultiErrorAppend( 116 errs, errors.New("only one of user_data or user_data_file can be specified")) 117 } else if c.UserDataFile != "" { 118 if _, err := os.Stat(c.UserDataFile); err != nil { 119 errs = packer.MultiErrorAppend( 120 errs, errors.New(fmt.Sprintf("user_data_file not found: %s", c.UserDataFile))) 121 } 122 } 123 124 if errs != nil && len(errs.Errors) > 0 { 125 return nil, nil, errs 126 } 127 128 common.ScrubConfig(c, c.APIToken) 129 return c, nil, nil 130 }