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