github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/cloudstack/config.go (about) 1 package cloudstack 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 ) 16 17 // Config holds all the details needed to configure the builder. 18 type Config struct { 19 common.PackerConfig `mapstructure:",squash"` 20 common.HTTPConfig `mapstructure:",squash"` 21 Comm communicator.Config `mapstructure:",squash"` 22 23 APIURL string `mapstructure:"api_url"` 24 APIKey string `mapstructure:"api_key"` 25 SecretKey string `mapstructure:"secret_key"` 26 AsyncTimeout time.Duration `mapstructure:"async_timeout"` 27 HTTPGetOnly bool `mapstructure:"http_get_only"` 28 SSLNoVerify bool `mapstructure:"ssl_no_verify"` 29 30 CIDRList []string `mapstructure:"cidr_list"` 31 CreateSecurityGroup bool `mapstructure:"create_security_group"` 32 DiskOffering string `mapstructure:"disk_offering"` 33 DiskSize int64 `mapstructure:"disk_size"` 34 Expunge bool `mapstructure:"expunge"` 35 Hypervisor string `mapstructure:"hypervisor"` 36 InstanceName string `mapstructure:"instance_name"` 37 Keypair string `mapstructure:"keypair"` 38 Network string `mapstructure:"network"` 39 Project string `mapstructure:"project"` 40 PublicIPAddress string `mapstructure:"public_ip_address"` 41 SecurityGroups []string `mapstructure:"security_groups"` 42 ServiceOffering string `mapstructure:"service_offering"` 43 SourceISO string `mapstructure:"source_iso"` 44 SourceTemplate string `mapstructure:"source_template"` 45 TemporaryKeypairName string `mapstructure:"temporary_keypair_name"` 46 UseLocalIPAddress bool `mapstructure:"use_local_ip_address"` 47 UserData string `mapstructure:"user_data"` 48 UserDataFile string `mapstructure:"user_data_file"` 49 Zone string `mapstructure:"zone"` 50 51 TemplateName string `mapstructure:"template_name"` 52 TemplateDisplayText string `mapstructure:"template_display_text"` 53 TemplateOS string `mapstructure:"template_os"` 54 TemplateFeatured bool `mapstructure:"template_featured"` 55 TemplatePublic bool `mapstructure:"template_public"` 56 TemplatePasswordEnabled bool `mapstructure:"template_password_enabled"` 57 TemplateRequiresHVM bool `mapstructure:"template_requires_hvm"` 58 TemplateScalable bool `mapstructure:"template_scalable"` 59 TemplateTag string `mapstructure:"template_tag"` 60 61 ctx interpolate.Context 62 } 63 64 // NewConfig parses and validates the given config. 65 func NewConfig(raws ...interface{}) (*Config, error) { 66 c := new(Config) 67 err := config.Decode(c, &config.DecodeOpts{ 68 Interpolate: true, 69 InterpolateContext: &c.ctx, 70 InterpolateFilter: &interpolate.RenderFilter{ 71 Exclude: []string{ 72 "user_data", 73 }, 74 }, 75 }, raws...) 76 if err != nil { 77 return nil, err 78 } 79 80 var errs *packer.MultiError 81 82 // Set some defaults. 83 if c.APIURL == "" { 84 // Default to environment variable for api_url, if it exists 85 c.APIURL = os.Getenv("CLOUDSTACK_API_URL") 86 } 87 88 if c.APIKey == "" { 89 // Default to environment variable for api_key, if it exists 90 c.APIKey = os.Getenv("CLOUDSTACK_API_KEY") 91 } 92 93 if c.SecretKey == "" { 94 // Default to environment variable for secret_key, if it exists 95 c.SecretKey = os.Getenv("CLOUDSTACK_SECRET_KEY") 96 } 97 98 if c.AsyncTimeout == 0 { 99 c.AsyncTimeout = 30 * time.Minute 100 } 101 102 if len(c.CIDRList) == 0 { 103 c.CIDRList = []string{"0.0.0.0/0"} 104 } 105 106 if c.InstanceName == "" { 107 c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) 108 } 109 110 if c.TemplateName == "" { 111 name, err := interpolate.Render("packer-{{timestamp}}", nil) 112 if err != nil { 113 errs = packer.MultiErrorAppend(errs, 114 fmt.Errorf("Unable to parse template name: %s ", err)) 115 } 116 117 c.TemplateName = name 118 } 119 120 if c.TemplateDisplayText == "" { 121 c.TemplateDisplayText = c.TemplateName 122 } 123 124 // If we are not given an explicit keypair, ssh_password or ssh_private_key_file, 125 // then create a temporary one, but only if the temporary_keypair_name has not 126 // been provided. 127 if c.Keypair == "" && c.TemporaryKeypairName == "" && 128 c.Comm.SSHPrivateKey == "" && c.Comm.SSHPassword == "" { 129 c.TemporaryKeypairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()) 130 } 131 132 // Process required parameters. 133 if c.APIURL == "" { 134 errs = packer.MultiErrorAppend(errs, errors.New("a api_url must be specified")) 135 } 136 137 if c.APIKey == "" { 138 errs = packer.MultiErrorAppend(errs, errors.New("a api_key must be specified")) 139 } 140 141 if c.SecretKey == "" { 142 errs = packer.MultiErrorAppend(errs, errors.New("a secret_key must be specified")) 143 } 144 145 if c.Network == "" { 146 errs = packer.MultiErrorAppend(errs, errors.New("a network must be specified")) 147 } 148 149 if c.CreateSecurityGroup && !c.Expunge { 150 errs = packer.MultiErrorAppend(errs, errors.New("auto creating a temporary security group requires expunge")) 151 } 152 153 if c.ServiceOffering == "" { 154 errs = packer.MultiErrorAppend(errs, errors.New("a service_offering must be specified")) 155 } 156 157 if c.SourceISO == "" && c.SourceTemplate == "" { 158 errs = packer.MultiErrorAppend( 159 errs, errors.New("either source_iso or source_template must be specified")) 160 } 161 162 if c.SourceISO != "" && c.SourceTemplate != "" { 163 errs = packer.MultiErrorAppend( 164 errs, errors.New("only one of source_iso or source_template can be specified")) 165 } 166 167 if c.SourceISO != "" && c.DiskOffering == "" { 168 errs = packer.MultiErrorAppend( 169 errs, errors.New("a disk_offering must be specified when using source_iso")) 170 } 171 172 if c.SourceISO != "" && c.Hypervisor == "" { 173 errs = packer.MultiErrorAppend( 174 errs, errors.New("a hypervisor must be specified when using source_iso")) 175 } 176 177 if c.TemplateOS == "" { 178 errs = packer.MultiErrorAppend(errs, errors.New("a template_os must be specified")) 179 } 180 181 if c.UserData != "" && c.UserDataFile != "" { 182 errs = packer.MultiErrorAppend( 183 errs, errors.New("only one of user_data or user_data_file can be specified")) 184 } 185 186 if c.UserDataFile != "" { 187 if _, err := os.Stat(c.UserDataFile); err != nil { 188 errs = packer.MultiErrorAppend( 189 errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) 190 } 191 } 192 193 if c.Zone == "" { 194 errs = packer.MultiErrorAppend(errs, errors.New("a zone must be specified")) 195 } 196 197 if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { 198 errs = packer.MultiErrorAppend(errs, es...) 199 } 200 201 // Check for errors and return if we have any. 202 if errs != nil && len(errs.Errors) > 0 { 203 return nil, errs 204 } 205 206 return c, nil 207 }