packer-cn/builder/digitalocean/config.go

144 lines
3.8 KiB
Go
Raw Normal View History

package digitalocean
import (
"errors"
"fmt"
"os"
2018-08-15 09:27:00 -04:00
"regexp"
"time"
2017-04-04 16:39:01 -04:00
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/mapstructure"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
2015-06-13 18:26:13 -04:00
Comm communicator.Config `mapstructure:",squash"`
APIToken string `mapstructure:"api_token"`
APIURL string `mapstructure:"api_url"`
Region string `mapstructure:"region"`
Size string `mapstructure:"size"`
Image string `mapstructure:"image"`
2015-06-13 18:26:13 -04:00
PrivateNetworking bool `mapstructure:"private_networking"`
2017-04-08 15:52:57 -04:00
Monitoring bool `mapstructure:"monitoring"`
IPv6 bool `mapstructure:"ipv6"`
2015-06-13 18:26:13 -04:00
SnapshotName string `mapstructure:"snapshot_name"`
2017-05-15 22:19:02 -04:00
SnapshotRegions []string `mapstructure:"snapshot_regions"`
2015-06-13 18:26:13 -04:00
StateTimeout time.Duration `mapstructure:"state_timeout"`
DropletName string `mapstructure:"droplet_name"`
UserData string `mapstructure:"user_data"`
UserDataFile string `mapstructure:"user_data_file"`
2018-07-30 09:55:06 -04:00
Tags []string `mapstructure:"tags"`
ctx interpolate.Context
}
func NewConfig(raws ...interface{}) (*Config, []string, error) {
c := new(Config)
var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{
Metadata: &md,
Interpolate: true,
InterpolateContext: &c.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"run_command",
},
},
}, raws...)
if err != nil {
return nil, nil, err
}
// Defaults
if c.APIToken == "" {
// Default to environment variable for api_token, if it exists
c.APIToken = os.Getenv("DIGITALOCEAN_API_TOKEN")
}
if c.APIURL == "" {
c.APIURL = os.Getenv("DIGITALOCEAN_API_URL")
}
if c.SnapshotName == "" {
def, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
panic(err)
}
// Default to packer-{{ unix timestamp (utc) }}
c.SnapshotName = def
}
if c.DropletName == "" {
// Default to packer-[time-ordered-uuid]
c.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
2015-06-13 18:26:13 -04:00
if c.StateTimeout == 0 {
// Default to 6 minute timeouts waiting for
// desired state. i.e waiting for droplet to become active
2015-06-13 18:26:13 -04:00
c.StateTimeout = 6 * time.Minute
}
var errs *packer.MultiError
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
2015-06-13 18:26:13 -04:00
errs = packer.MultiErrorAppend(errs, es...)
}
if c.APIToken == "" {
// Required configurations that will display errors if not set
errs = packer.MultiErrorAppend(
errs, errors.New("api_token for auth must be specified"))
}
if c.Region == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("region is required"))
}
if c.Size == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("size is required"))
}
if c.Image == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("image is required"))
}
if c.UserData != "" && c.UserDataFile != "" {
errs = packer.MultiErrorAppend(
errs, errors.New("only one of user_data or user_data_file can be specified"))
} else if c.UserDataFile != "" {
if _, err := os.Stat(c.UserDataFile); err != nil {
errs = packer.MultiErrorAppend(
errs, errors.New(fmt.Sprintf("user_data_file not found: %s", c.UserDataFile)))
}
}
2018-07-30 09:55:06 -04:00
if c.Tags == nil {
c.Tags = make([]string, 0)
2018-07-30 09:52:40 -04:00
}
2018-08-15 09:27:00 -04:00
tagRe := regexp.MustCompile("^[[:alnum:]:_-]{1,255}$")
for _, t := range c.Tags {
if !tagRe.MatchString(t) {
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("invalid tag: %s", t)))
}
}
2018-07-30 09:52:40 -04:00
if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs
}
common.ScrubConfig(c, c.APIToken)
return c, nil, nil
}