packer-cn/builder/cloudstack/config.go

209 lines
6.8 KiB
Go

package cloudstack
import (
"errors"
"fmt"
"os"
"time"
"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"
)
// Config holds all the details needed to configure the builder.
type Config struct {
common.PackerConfig `mapstructure:",squash"`
common.HTTPConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"`
APIURL string `mapstructure:"api_url"`
APIKey string `mapstructure:"api_key"`
SecretKey string `mapstructure:"secret_key"`
AsyncTimeout time.Duration `mapstructure:"async_timeout"`
HTTPGetOnly bool `mapstructure:"http_get_only"`
SSLNoVerify bool `mapstructure:"ssl_no_verify"`
CIDRList []string `mapstructure:"cidr_list"`
CreateSecurityGroup bool `mapstructure:"create_security_group"`
DiskOffering string `mapstructure:"disk_offering"`
DiskSize int64 `mapstructure:"disk_size"`
Expunge bool `mapstructure:"expunge"`
Hypervisor string `mapstructure:"hypervisor"`
InstanceName string `mapstructure:"instance_name"`
Network string `mapstructure:"network"`
Project string `mapstructure:"project"`
PublicIPAddress string `mapstructure:"public_ip_address"`
PublicPort int `mapstructure:"public_port"`
SecurityGroups []string `mapstructure:"security_groups"`
ServiceOffering string `mapstructure:"service_offering"`
PreventFirewallChanges bool `mapstructure:"prevent_firewall_changes"`
SourceISO string `mapstructure:"source_iso"`
SourceTemplate string `mapstructure:"source_template"`
TemporaryKeypairName string `mapstructure:"temporary_keypair_name"`
UseLocalIPAddress bool `mapstructure:"use_local_ip_address"`
UserData string `mapstructure:"user_data"`
UserDataFile string `mapstructure:"user_data_file"`
Zone string `mapstructure:"zone"`
TemplateName string `mapstructure:"template_name"`
TemplateDisplayText string `mapstructure:"template_display_text"`
TemplateOS string `mapstructure:"template_os"`
TemplateFeatured bool `mapstructure:"template_featured"`
TemplatePublic bool `mapstructure:"template_public"`
TemplatePasswordEnabled bool `mapstructure:"template_password_enabled"`
TemplateRequiresHVM bool `mapstructure:"template_requires_hvm"`
TemplateScalable bool `mapstructure:"template_scalable"`
TemplateTag string `mapstructure:"template_tag"`
ctx interpolate.Context
}
// NewConfig parses and validates the given config.
func NewConfig(raws ...interface{}) (*Config, error) {
c := new(Config)
err := config.Decode(c, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &c.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"user_data",
},
},
}, raws...)
if err != nil {
return nil, err
}
var errs *packer.MultiError
// Set some defaults.
if c.APIURL == "" {
// Default to environment variable for api_url, if it exists
c.APIURL = os.Getenv("CLOUDSTACK_API_URL")
}
if c.APIKey == "" {
// Default to environment variable for api_key, if it exists
c.APIKey = os.Getenv("CLOUDSTACK_API_KEY")
}
if c.SecretKey == "" {
// Default to environment variable for secret_key, if it exists
c.SecretKey = os.Getenv("CLOUDSTACK_SECRET_KEY")
}
if c.AsyncTimeout == 0 {
c.AsyncTimeout = 30 * time.Minute
}
if len(c.CIDRList) == 0 {
c.CIDRList = []string{"0.0.0.0/0"}
}
if c.InstanceName == "" {
c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
if c.TemplateName == "" {
name, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Unable to parse template name: %s ", err))
}
c.TemplateName = name
}
if c.TemplateDisplayText == "" {
c.TemplateDisplayText = c.TemplateName
}
// If we are not given an explicit keypair, ssh_password or ssh_private_key_file,
// then create a temporary one, but only if the temporary_keypair_name has not
// been provided.
if c.Comm.SSHKeyPairName == "" && c.Comm.SSHTemporaryKeyPairName == "" &&
c.Comm.SSHPrivateKeyFile == "" && c.Comm.SSHPassword == "" {
c.Comm.SSHTemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
}
// Process required parameters.
if c.APIURL == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a api_url must be specified"))
}
if c.APIKey == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a api_key must be specified"))
}
if c.SecretKey == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a secret_key must be specified"))
}
if c.Network == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a network must be specified"))
}
if c.CreateSecurityGroup && !c.Expunge {
errs = packer.MultiErrorAppend(errs, errors.New("auto creating a temporary security group requires expunge"))
}
if c.ServiceOffering == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a service_offering must be specified"))
}
if c.SourceISO == "" && c.SourceTemplate == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("either source_iso or source_template must be specified"))
}
if c.SourceISO != "" && c.SourceTemplate != "" {
errs = packer.MultiErrorAppend(
errs, errors.New("only one of source_iso or source_template can be specified"))
}
if c.SourceISO != "" && c.DiskOffering == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a disk_offering must be specified when using source_iso"))
}
if c.SourceISO != "" && c.Hypervisor == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a hypervisor must be specified when using source_iso"))
}
if c.TemplateOS == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a template_os must be specified"))
}
if c.UserData != "" && c.UserDataFile != "" {
errs = packer.MultiErrorAppend(
errs, errors.New("only one of user_data or user_data_file can be specified"))
}
if c.UserDataFile != "" {
if _, err := os.Stat(c.UserDataFile); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile))
}
}
if c.Zone == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a zone must be specified"))
}
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packer.MultiErrorAppend(errs, es...)
}
// Check for errors and return if we have any.
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
return c, nil
}