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