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