From 45d3f28c67c5aeff32316e1652beeaa3ab548238 Mon Sep 17 00:00:00 2001 From: Paul Meyer Date: Mon, 27 May 2019 06:20:11 +0000 Subject: [PATCH] Add StepCreateNewDisk --- builder/azure/chroot/builder.go | 55 ++++++++++++ builder/azure/chroot/step_create_new_disk.go | 88 ++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 builder/azure/chroot/step_create_new_disk.go diff --git a/builder/azure/chroot/builder.go b/builder/azure/chroot/builder.go index 073c13aac..add0a04c6 100644 --- a/builder/azure/chroot/builder.go +++ b/builder/azure/chroot/builder.go @@ -3,9 +3,13 @@ package chroot import ( "context" "errors" + "fmt" + "log" "runtime" + "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute" azcommon "github.com/hashicorp/packer/builder/azure/common" + "github.com/hashicorp/packer/builder/azure/common/client" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/multistep" @@ -16,6 +20,11 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` + FromScratch bool `mapstructure:"from_scratch"` + + OSDiskSizeGB int32 `mapstructure:"osdisk_size_gb"` + OSDiskStorageAccountType string `mapstructure:"osdisk_storageaccounttype"` + ctx interpolate.Context } @@ -36,10 +45,22 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { }, }, raws...) + // defaults + if b.config.OSDiskStorageAccountType == "" { + b.config.OSDiskStorageAccountType = string(compute.PremiumLRS) + } + // checks, accumulate any errors or warnings var errs *packer.MultiError var warns []string + if b.config.FromScratch { + if b.config.OSDiskSizeGB == 0 { + errs = packer.MultiErrorAppend( + errs, errors.New("osdisk_size_gb is required with from_scratch.")) + } + } + if err != nil { return nil, err } @@ -51,15 +72,49 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("The azure-chroot builder only works on Linux environments.") } + var azcli client.AzureClientSet + // Setup the state bag and initial state for the steps state := new(multistep.BasicStateBag) state.Put("config", &b.config) state.Put("hook", hook) state.Put("ui", ui) + info, err := azcli.MetadataClient().GetComputeInfo() + if err != nil { + log.Printf("MetadataClient().GetComputeInfo(): error: %+v", err) + err := fmt.Errorf( + "Error retrieving information ARM resource ID and location" + + "of the VM that Packer is running on.\n" + + "Please verify that Packer is running on a proper Azure VM.") + ui.Error(err.Error()) + return nil, err + } + + osDiskName := "PackerBuiltOsDisk" + + state.Put("instance", info) + if err != nil { + return nil, err + } + // Build the steps var steps []multistep.Step + if !b.config.FromScratch { + panic("Only from_scratch is currently implemented") + // create disk from PIR / managed image (warn on non-linux images) + } else { + steps = append(steps, + &StepCreateNewDisk{ + SubscriptionID: info.SubscriptionID, + ResourceGroup: info.ResourceGroupName, + DiskName: osDiskName, + DiskSizeGB: b.config.OSDiskSizeGB, + DiskStorageAccountType: b.config.OSDiskStorageAccountType, + }) + } + // Run! b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(ctx, state) diff --git a/builder/azure/chroot/step_create_new_disk.go b/builder/azure/chroot/step_create_new_disk.go new file mode 100644 index 000000000..098adb25f --- /dev/null +++ b/builder/azure/chroot/step_create_new_disk.go @@ -0,0 +1,88 @@ +package chroot + +import ( + "context" + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" + "github.com/Azure/go-autorest/autorest/to" + "github.com/hashicorp/packer/builder/azure/common/client" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +var _ multistep.Step = &StepCreateNewDisk{} + +type StepCreateNewDisk struct { + SubscriptionID, ResourceGroup, DiskName string + DiskSizeGB int32 // optional, ignored if 0 + DiskStorageAccountType string // from compute.DiskStorageAccountTypes +} + +func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + azcli := state.Get("azureclient").(client.AzureClientSet) + ui := state.Get("ui").(packer.Ui) + + diskResourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/disks/%s", + s.SubscriptionID, + s.ResourceGroup, + s.DiskName) + state.Put("os_disk_resource_id", diskResourceID) + ui.Say(fmt.Sprintf("Creating disk '%s'", diskResourceID)) + + disk := compute.Disk{ + Sku: &compute.DiskSku{ + Name: "", + }, + //Zones: nil, + DiskProperties: &compute.DiskProperties{ + OsType: "", + HyperVGeneration: "", + CreationData: &compute.CreationData{ + CreateOption: compute.Empty, + }, + DiskSizeGB: to.Int32Ptr(s.DiskSizeGB), + }, + //Tags: map[string]*string{ + } + + if s.DiskSizeGB > 0 { + disk.DiskProperties.DiskSizeGB = to.Int32Ptr(s.DiskSizeGB) + } + + f, err := azcli.DisksClient().CreateOrUpdate(ctx, s.ResourceGroup, s.DiskName, disk) + if err == nil { + err = f.WaitForCompletionRef(ctx, azcli.PollClient()) + } + if err != nil { + log.Printf("StepCreateNewDisk.Run: error: %+v", err) + err := fmt.Errorf( + "error creating new disk '%s': %v", diskResourceID, err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s StepCreateNewDisk) Cleanup(state multistep.StateBag) { + azcli := state.Get("azureclient").(client.AzureClientSet) + ui := state.Get("ui").(packer.Ui) + + diskResourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/disks/%s", + s.SubscriptionID, + s.ResourceGroup, + s.DiskName) + ui.Say(fmt.Sprintf("Deleting disk '%s'", diskResourceID)) + + f, err := azcli.DisksClient().Delete(context.TODO(), s.ResourceGroup, s.DiskName) + if err == nil { + err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient()) + } + if err != nil { + log.Printf("StepCreateNewDisk.Cleanup: error: %+v", err) + ui.Error(fmt.Sprintf("Error deleting new disk '%s': %v.", diskResourceID, err)) + } +}