github.com/kikitux/packer@v0.10.1-0.20160322154024-6237df566f9f/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  
    11  	"github.com/mitchellh/packer/builder/azure/common/constants"
    12  	"github.com/mitchellh/packer/builder/azure/common/lin"
    13  
    14  	"github.com/Azure/go-autorest/autorest/azure"
    15  
    16  	"github.com/mitchellh/multistep"
    17  	"github.com/mitchellh/packer/common"
    18  	"github.com/mitchellh/packer/helper/communicator"
    19  	"github.com/mitchellh/packer/packer"
    20  )
    21  
    22  type Builder struct {
    23  	config   *Config
    24  	stateBag multistep.StateBag
    25  	runner   multistep.Runner
    26  }
    27  
    28  const (
    29  	DefaultPublicIPAddressName = "packerPublicIP"
    30  )
    31  
    32  func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
    33  	c, warnings, errs := newConfig(raws...)
    34  	if errs != nil {
    35  		return warnings, errs
    36  	}
    37  
    38  	b.config = c
    39  
    40  	b.stateBag = new(multistep.BasicStateBag)
    41  	err := b.configureStateBag(b.stateBag)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	return warnings, errs
    47  }
    48  
    49  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    50  	ui.Say("Preparing builder ...")
    51  
    52  	b.stateBag.Put("hook", hook)
    53  	b.stateBag.Put(constants.Ui, ui)
    54  
    55  	servicePrincipalToken, err := b.createServicePrincipalToken()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	ui.Message("Creating Azure Resource Manager (ARM) client ...")
    61  	azureClient, err := NewAzureClient(b.config.SubscriptionID, b.config.ResourceGroupName, b.config.StorageAccount, servicePrincipalToken)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	steps := []multistep.Step{
    67  		NewStepCreateResourceGroup(azureClient, ui),
    68  		NewStepValidateTemplate(azureClient, ui),
    69  		NewStepDeployTemplate(azureClient, ui),
    70  		NewStepGetIPAddress(azureClient, ui),
    71  		&communicator.StepConnectSSH{
    72  			Config:    &b.config.Comm,
    73  			Host:      lin.SSHHost,
    74  			SSHConfig: lin.SSHConfig(b.config.UserName),
    75  		},
    76  		&common.StepProvision{},
    77  		NewStepGetOSDisk(azureClient, ui),
    78  		NewStepPowerOffCompute(azureClient, ui),
    79  		NewStepCaptureImage(azureClient, ui),
    80  		NewStepDeleteResourceGroup(azureClient, ui),
    81  		NewStepDeleteOSDisk(azureClient, ui),
    82  	}
    83  
    84  	if b.config.PackerDebug {
    85  		ui.Message(fmt.Sprintf("temp admin user: '%s'", b.config.UserName))
    86  		ui.Message(fmt.Sprintf("temp admin password: '%s'", b.config.Password))
    87  	}
    88  
    89  	b.runner = b.createRunner(&steps, ui)
    90  	b.runner.Run(b.stateBag)
    91  
    92  	// Report any errors.
    93  	if rawErr, ok := b.stateBag.GetOk(constants.Error); ok {
    94  		return nil, rawErr.(error)
    95  	}
    96  
    97  	// If we were interrupted or cancelled, then just exit.
    98  	if _, ok := b.stateBag.GetOk(multistep.StateCancelled); ok {
    99  		return nil, errors.New("Build was cancelled.")
   100  	}
   101  
   102  	if _, ok := b.stateBag.GetOk(multistep.StateHalted); ok {
   103  		return nil, errors.New("Build was halted.")
   104  	}
   105  
   106  	return &artifact{}, nil
   107  }
   108  
   109  func (b *Builder) Cancel() {
   110  	if b.runner != nil {
   111  		log.Println("Cancelling the step runner...")
   112  		b.runner.Cancel()
   113  	}
   114  }
   115  
   116  func (b *Builder) createRunner(steps *[]multistep.Step, ui packer.Ui) multistep.Runner {
   117  	if b.config.PackerDebug {
   118  		return &multistep.DebugRunner{
   119  			Steps:   *steps,
   120  			PauseFn: common.MultistepDebugFn(ui),
   121  		}
   122  	}
   123  
   124  	return &multistep.BasicRunner{
   125  		Steps: *steps,
   126  	}
   127  }
   128  
   129  func (b *Builder) configureStateBag(stateBag multistep.StateBag) error {
   130  	stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey)
   131  	stateBag.Put(constants.PrivateKey, b.config.sshPrivateKey)
   132  
   133  	stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
   134  	stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)
   135  	stateBag.Put(constants.ArmLocation, b.config.Location)
   136  	stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName)
   137  	stateBag.Put(constants.ArmTemplateParameters, b.config.toTemplateParameters())
   138  	stateBag.Put(constants.ArmVirtualMachineCaptureParameters, b.config.toVirtualMachineCaptureParameters())
   139  
   140  	stateBag.Put(constants.ArmPublicIPAddressName, DefaultPublicIPAddressName)
   141  
   142  	return nil
   143  }
   144  
   145  func (b *Builder) createServicePrincipalToken() (*azure.ServicePrincipalToken, error) {
   146  	oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(b.config.TenantID)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	spt, err := azure.NewServicePrincipalToken(
   152  		*oauthConfig,
   153  		b.config.ClientID,
   154  		b.config.ClientSecret,
   155  		azure.PublicCloud.ResourceManagerEndpoint)
   156  
   157  	return spt, err
   158  }