github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/azure/arm/builder.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 "errors" 8 "fmt" 9 "log" 10 "strings" 11 "time" 12 13 packerAzureCommon "github.com/mitchellh/packer/builder/azure/common" 14 15 "github.com/Azure/go-autorest/autorest/azure" 16 17 "github.com/mitchellh/packer/builder/azure/common/constants" 18 "github.com/mitchellh/packer/builder/azure/common/lin" 19 20 "github.com/mitchellh/multistep" 21 packerCommon "github.com/mitchellh/packer/common" 22 "github.com/mitchellh/packer/helper/communicator" 23 "github.com/mitchellh/packer/packer" 24 ) 25 26 type Builder struct { 27 config *Config 28 stateBag multistep.StateBag 29 runner multistep.Runner 30 } 31 32 const ( 33 DefaultNicName = "packerNic" 34 DefaultPublicIPAddressName = "packerPublicIP" 35 DefaultSasBlobContainer = "system/Microsoft.Compute" 36 DefaultSasBlobPermission = "r" 37 DefaultSecretName = "packerKeyVaultSecret" 38 ) 39 40 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 41 c, warnings, errs := newConfig(raws...) 42 if errs != nil { 43 return warnings, errs 44 } 45 46 b.config = c 47 48 b.stateBag = new(multistep.BasicStateBag) 49 b.configureStateBag(b.stateBag) 50 b.setTemplateParameters(b.stateBag) 51 52 return warnings, errs 53 } 54 55 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 56 ui.Say("Running builder ...") 57 58 if err := newConfigRetriever().FillParameters(b.config); err != nil { 59 return nil, err 60 } 61 62 log.Print(":: Configuration") 63 packerAzureCommon.DumpConfig(b.config, func(s string) { log.Print(s) }) 64 65 b.stateBag.Put("hook", hook) 66 b.stateBag.Put(constants.Ui, ui) 67 68 spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say) 69 if err != nil { 70 return nil, err 71 } 72 73 ui.Message("Creating Azure Resource Manager (ARM) client ...") 74 azureClient, err := NewAzureClient( 75 b.config.SubscriptionID, 76 b.config.ResourceGroupName, 77 b.config.StorageAccount, 78 b.config.cloudEnvironment, 79 spnCloud, 80 spnKeyVault) 81 82 if err != nil { 83 return nil, err 84 } 85 86 resolver := newResourceResolver(azureClient) 87 if err := resolver.Resolve(b.config); err != nil { 88 return nil, err 89 } 90 91 b.config.storageAccountBlobEndpoint, err = b.getBlobEndpoint(azureClient, b.config.ResourceGroupName, b.config.StorageAccount) 92 if err != nil { 93 return nil, err 94 } 95 96 endpointConnectType := PublicEndpoint 97 if b.isPrivateNetworkCommunication() { 98 endpointConnectType = PrivateEndpoint 99 } 100 101 b.setTemplateParameters(b.stateBag) 102 var steps []multistep.Step 103 104 if b.config.OSType == constants.Target_Linux { 105 steps = []multistep.Step{ 106 NewStepCreateResourceGroup(azureClient, ui), 107 NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), 108 NewStepDeployTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), 109 NewStepGetIPAddress(azureClient, ui, endpointConnectType), 110 &communicator.StepConnectSSH{ 111 Config: &b.config.Comm, 112 Host: lin.SSHHost, 113 SSHConfig: lin.SSHConfig(b.config.UserName), 114 }, 115 &packerCommon.StepProvision{}, 116 NewStepGetOSDisk(azureClient, ui), 117 NewStepPowerOffCompute(azureClient, ui), 118 NewStepCaptureImage(azureClient, ui), 119 NewStepDeleteResourceGroup(azureClient, ui), 120 NewStepDeleteOSDisk(azureClient, ui), 121 } 122 } else if b.config.OSType == constants.Target_Windows { 123 steps = []multistep.Step{ 124 NewStepCreateResourceGroup(azureClient, ui), 125 NewStepValidateTemplate(azureClient, ui, b.config, GetKeyVaultDeployment), 126 NewStepDeployTemplate(azureClient, ui, b.config, GetKeyVaultDeployment), 127 NewStepGetCertificate(azureClient, ui), 128 NewStepSetCertificate(b.config, ui), 129 NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), 130 NewStepDeployTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), 131 NewStepGetIPAddress(azureClient, ui, endpointConnectType), 132 &communicator.StepConnectWinRM{ 133 Config: &b.config.Comm, 134 Host: func(stateBag multistep.StateBag) (string, error) { 135 return stateBag.Get(constants.SSHHost).(string), nil 136 }, 137 WinRMConfig: func(multistep.StateBag) (*communicator.WinRMConfig, error) { 138 return &communicator.WinRMConfig{ 139 Username: b.config.UserName, 140 Password: b.config.tmpAdminPassword, 141 }, nil 142 }, 143 }, 144 &packerCommon.StepProvision{}, 145 NewStepGetOSDisk(azureClient, ui), 146 NewStepPowerOffCompute(azureClient, ui), 147 NewStepCaptureImage(azureClient, ui), 148 NewStepDeleteResourceGroup(azureClient, ui), 149 NewStepDeleteOSDisk(azureClient, ui), 150 } 151 } else { 152 return nil, fmt.Errorf("Builder does not support the os_type '%s'", b.config.OSType) 153 } 154 155 if b.config.PackerDebug { 156 ui.Message(fmt.Sprintf("temp admin user: '%s'", b.config.UserName)) 157 ui.Message(fmt.Sprintf("temp admin password: '%s'", b.config.Password)) 158 } 159 160 b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui) 161 b.runner.Run(b.stateBag) 162 163 // Report any errors. 164 if rawErr, ok := b.stateBag.GetOk(constants.Error); ok { 165 return nil, rawErr.(error) 166 } 167 168 // If we were interrupted or cancelled, then just exit. 169 if _, ok := b.stateBag.GetOk(multistep.StateCancelled); ok { 170 return nil, errors.New("Build was cancelled.") 171 } 172 173 if _, ok := b.stateBag.GetOk(multistep.StateHalted); ok { 174 return nil, errors.New("Build was halted.") 175 } 176 177 if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { 178 return NewArtifact( 179 template.(*CaptureTemplate), 180 func(name string) string { 181 month := time.Now().AddDate(0, 1, 0).UTC() 182 sasUrl, _ := azureClient.BlobStorageClient.GetBlobSASURI(DefaultSasBlobContainer, name, month, DefaultSasBlobPermission) 183 return sasUrl 184 }) 185 } 186 187 return &Artifact{}, nil 188 } 189 190 func (b *Builder) isPrivateNetworkCommunication() bool { 191 return b.config.VirtualNetworkName != "" 192 } 193 194 func (b *Builder) Cancel() { 195 if b.runner != nil { 196 log.Println("Cancelling the step runner...") 197 b.runner.Cancel() 198 } 199 } 200 201 func (b *Builder) getBlobEndpoint(client *AzureClient, resourceGroupName string, storageAccountName string) (string, error) { 202 account, err := client.AccountsClient.GetProperties(resourceGroupName, storageAccountName) 203 if err != nil { 204 return "", err 205 } 206 207 return *account.Properties.PrimaryEndpoints.Blob, nil 208 } 209 210 func (b *Builder) configureStateBag(stateBag multistep.StateBag) { 211 stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey) 212 stateBag.Put(constants.PrivateKey, b.config.sshPrivateKey) 213 214 stateBag.Put(constants.ArmTags, &b.config.AzureTags) 215 stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName) 216 stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName) 217 stateBag.Put(constants.ArmKeyVaultName, b.config.tmpKeyVaultName) 218 stateBag.Put(constants.ArmLocation, b.config.Location) 219 stateBag.Put(constants.ArmNicName, DefaultNicName) 220 stateBag.Put(constants.ArmPublicIPAddressName, DefaultPublicIPAddressName) 221 stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName) 222 stateBag.Put(constants.ArmStorageAccountName, b.config.StorageAccount) 223 } 224 225 func (b *Builder) setTemplateParameters(stateBag multistep.StateBag) { 226 stateBag.Put(constants.ArmVirtualMachineCaptureParameters, b.config.toVirtualMachineCaptureParameters()) 227 } 228 229 func (b *Builder) getServicePrincipalTokens(say func(string)) (*azure.ServicePrincipalToken, *azure.ServicePrincipalToken, error) { 230 var servicePrincipalToken *azure.ServicePrincipalToken 231 var servicePrincipalTokenVault *azure.ServicePrincipalToken 232 233 var err error 234 235 if b.config.useDeviceLogin { 236 servicePrincipalToken, err = packerAzureCommon.Authenticate(*b.config.cloudEnvironment, b.config.TenantID, say) 237 if err != nil { 238 return nil, nil, err 239 } 240 } else { 241 auth := NewAuthenticate(*b.config.cloudEnvironment, b.config.ClientID, b.config.ClientSecret, b.config.TenantID) 242 243 servicePrincipalToken, err = auth.getServicePrincipalToken() 244 if err != nil { 245 return nil, nil, err 246 } 247 248 servicePrincipalTokenVault, err = auth.getServicePrincipalTokenWithResource( 249 strings.TrimRight(b.config.cloudEnvironment.KeyVaultEndpoint, "/")) 250 251 if err != nil { 252 return nil, nil, err 253 } 254 } 255 256 return servicePrincipalToken, servicePrincipalTokenVault, nil 257 }