github.com/kikitux/packer@v0.10.1-0.20160322154024-6237df566f9f/builder/azure/arm/config.go (about) 1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT License. See the LICENSE file in builder/azure for license information. 3 4 package arm 5 6 import ( 7 "encoding/base64" 8 "fmt" 9 "io/ioutil" 10 "time" 11 12 "golang.org/x/crypto/ssh" 13 14 "github.com/Azure/azure-sdk-for-go/arm/compute" 15 "github.com/Azure/go-autorest/autorest/to" 16 17 "github.com/mitchellh/packer/common" 18 "github.com/mitchellh/packer/helper/communicator" 19 "github.com/mitchellh/packer/helper/config" 20 "github.com/mitchellh/packer/packer" 21 "github.com/mitchellh/packer/template/interpolate" 22 ) 23 24 const ( 25 DefaultUserName = "packer" 26 DefaultVMSize = "Standard_A1" 27 ) 28 29 type Config struct { 30 common.PackerConfig `mapstructure:",squash"` 31 32 // Authentication via OAUTH 33 ClientID string `mapstructure:"client_id"` 34 ClientSecret string `mapstructure:"client_secret"` 35 TenantID string `mapstructure:"tenant_id"` 36 SubscriptionID string `mapstructure:"subscription_id"` 37 38 // Capture 39 CaptureNamePrefix string `mapstructure:"capture_name_prefix"` 40 CaptureContainerName string `mapstructure:"capture_container_name"` 41 42 // Compute 43 ImagePublisher string `mapstructure:"image_publisher"` 44 ImageOffer string `mapstructure:"image_offer"` 45 ImageSku string `mapstructure:"image_sku"` 46 Location string `mapstructure:"location"` 47 VMSize string `mapstructure:"vm_size"` 48 49 // Deployment 50 ResourceGroupName string `mapstructure:"resource_group_name"` 51 StorageAccount string `mapstructure:"storage_account"` 52 53 // Runtime Values 54 UserName string 55 Password string 56 tmpAdminPassword string 57 tmpResourceGroupName string 58 tmpComputeName string 59 tmpDeploymentName string 60 tmpOSDiskName string 61 62 // Authentication with the VM via SSH 63 sshAuthorizedKey string 64 sshPrivateKey string 65 66 Comm communicator.Config `mapstructure:",squash"` 67 ctx *interpolate.Context 68 } 69 70 // If we ever feel the need to support more templates consider moving this 71 // method to its own factory class. 72 func (c *Config) toTemplateParameters() *TemplateParameters { 73 return &TemplateParameters{ 74 AdminUsername: &TemplateParameter{c.UserName}, 75 AdminPassword: &TemplateParameter{c.Password}, 76 DnsNameForPublicIP: &TemplateParameter{c.tmpComputeName}, 77 ImageOffer: &TemplateParameter{c.ImageOffer}, 78 ImagePublisher: &TemplateParameter{c.ImagePublisher}, 79 ImageSku: &TemplateParameter{c.ImageSku}, 80 OSDiskName: &TemplateParameter{c.tmpOSDiskName}, 81 SshAuthorizedKey: &TemplateParameter{c.sshAuthorizedKey}, 82 StorageAccountName: &TemplateParameter{c.StorageAccount}, 83 VMSize: &TemplateParameter{c.VMSize}, 84 VMName: &TemplateParameter{c.tmpComputeName}, 85 } 86 } 87 88 func (c *Config) toVirtualMachineCaptureParameters() *compute.VirtualMachineCaptureParameters { 89 return &compute.VirtualMachineCaptureParameters{ 90 DestinationContainerName: &c.CaptureContainerName, 91 VhdPrefix: &c.CaptureNamePrefix, 92 OverwriteVhds: to.BoolPtr(false), 93 } 94 } 95 96 func newConfig(raws ...interface{}) (*Config, []string, error) { 97 var c Config 98 99 err := config.Decode(&c, &config.DecodeOpts{ 100 Interpolate: true, 101 InterpolateContext: c.ctx, 102 }, raws...) 103 104 if err != nil { 105 return nil, nil, err 106 } 107 108 provideDefaultValues(&c) 109 setRuntimeValues(&c) 110 setUserNamePassword(&c) 111 112 err = setSshValues(&c) 113 if err != nil { 114 return nil, nil, err 115 } 116 117 var errs *packer.MultiError 118 errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(c.ctx)...) 119 120 assertRequiredParametersSet(&c, errs) 121 if errs != nil && len(errs.Errors) > 0 { 122 return nil, nil, errs 123 } 124 125 return &c, nil, nil 126 } 127 128 func setSshValues(c *Config) error { 129 if c.Comm.SSHTimeout == 0 { 130 c.Comm.SSHTimeout = 20 * time.Minute 131 } 132 133 if c.Comm.SSHPrivateKey != "" { 134 privateKeyBytes, err := ioutil.ReadFile(c.Comm.SSHPrivateKey) 135 if err != nil { 136 panic(err) 137 } 138 signer, err := ssh.ParsePrivateKey(privateKeyBytes) 139 if err != nil { 140 panic(err) 141 } 142 143 publicKey := signer.PublicKey() 144 c.sshAuthorizedKey = fmt.Sprintf("%s %s packer Azure Deployment%s", 145 publicKey.Type(), 146 base64.StdEncoding.EncodeToString(publicKey.Marshal()), 147 time.Now().Format(time.RFC3339)) 148 c.sshPrivateKey = string(privateKeyBytes) 149 150 } else { 151 sshKeyPair, err := NewOpenSshKeyPair() 152 if err != nil { 153 return err 154 } 155 156 c.sshAuthorizedKey = sshKeyPair.AuthorizedKey() 157 c.sshPrivateKey = sshKeyPair.PrivateKey() 158 } 159 160 return nil 161 } 162 163 func setRuntimeValues(c *Config) { 164 var tempName = NewTempName() 165 166 c.tmpAdminPassword = tempName.AdminPassword 167 c.tmpComputeName = tempName.ComputeName 168 c.tmpDeploymentName = tempName.DeploymentName 169 // c.tmpResourceGroupName = c.ResourceGroupName 170 c.tmpResourceGroupName = tempName.ResourceGroupName 171 c.tmpOSDiskName = tempName.OSDiskName 172 } 173 174 func setUserNamePassword(c *Config) { 175 if c.Comm.SSHUsername == "" { 176 c.Comm.SSHUsername = DefaultUserName 177 } 178 179 c.UserName = c.Comm.SSHUsername 180 181 if c.Comm.SSHPassword != "" { 182 c.Password = c.Comm.SSHPassword 183 } else { 184 c.Password = c.tmpAdminPassword 185 } 186 } 187 188 func provideDefaultValues(c *Config) { 189 if c.VMSize == "" { 190 c.VMSize = DefaultVMSize 191 } 192 } 193 194 func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { 195 ///////////////////////////////////////////// 196 // Authentication via OAUTH 197 198 if c.ClientID == "" { 199 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A client_id must be specified")) 200 } 201 202 if c.ClientSecret == "" { 203 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A client_secret must be specified")) 204 } 205 206 if c.TenantID == "" { 207 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A tenant_id must be specified")) 208 } 209 210 if c.SubscriptionID == "" { 211 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A subscription_id must be specified")) 212 } 213 214 ///////////////////////////////////////////// 215 // Capture 216 if c.CaptureContainerName == "" { 217 errs = packer.MultiErrorAppend(errs, fmt.Errorf("An capture_container_name must be specified")) 218 } 219 220 if c.CaptureNamePrefix == "" { 221 errs = packer.MultiErrorAppend(errs, fmt.Errorf("An capture_name_prefix must be specified")) 222 } 223 224 ///////////////////////////////////////////// 225 // Compute 226 227 if c.ImagePublisher == "" { 228 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A image_publisher must be specified")) 229 } 230 231 if c.ImageOffer == "" { 232 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A image_offer must be specified")) 233 } 234 235 if c.ImageSku == "" { 236 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A image_sku must be specified")) 237 } 238 239 if c.Location == "" { 240 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A location must be specified")) 241 } 242 243 ///////////////////////////////////////////// 244 // Deployment 245 246 if c.StorageAccount == "" { 247 errs = packer.MultiErrorAppend(errs, fmt.Errorf("A storage_account must be specified")) 248 } 249 }