1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
package openstack
import (
"context"
"fmt"
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
)
type StepCreateVolume struct {
UseBlockStorageVolume bool
VolumeName string
VolumeType string
VolumeAvailabilityZone string
volumeID string
doCleanup bool
}
func (s *StepCreateVolume) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
// Proceed only if block storage volume is required.
if !s.UseBlockStorageVolume {
return multistep.ActionContinue
}
config := state.Get("config").(*Config)
ui := state.Get("ui").(packersdk.Ui)
sourceImage := state.Get("source_image").(string)
// We will need Block Storage and Image services clients.
blockStorageClient, err := config.blockStorageV3Client()
if err != nil {
err = fmt.Errorf("Error initializing block storage client: %s", err)
state.Put("error", err)
return multistep.ActionHalt
}
volumeSize := config.VolumeSize
// Get needed volume size from the source image.
if volumeSize == 0 {
imageClient, err := config.imageV2Client()
if err != nil {
err = fmt.Errorf("Error initializing image client: %s", err)
state.Put("error", err)
return multistep.ActionHalt
}
volumeSize, err = GetVolumeSize(imageClient, sourceImage)
if err != nil {
err := fmt.Errorf("Error creating volume: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
ui.Say("Creating volume...")
volumeOpts := volumes.CreateOpts{
Size: volumeSize,
VolumeType: s.VolumeType,
AvailabilityZone: s.VolumeAvailabilityZone,
Name: s.VolumeName,
ImageID: sourceImage,
Metadata: config.ImageMetadata,
}
volume, err := volumes.Create(blockStorageClient, volumeOpts).Extract()
if err != nil {
err := fmt.Errorf("Error creating volume: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// Wait for volume to become available.
ui.Say(fmt.Sprintf("Waiting for volume %s (volume id: %s) to become available...", config.VolumeName, volume.ID))
if err := WaitForVolume(blockStorageClient, volume.ID); err != nil {
err := fmt.Errorf("Error waiting for volume: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// Volume was created, so remember to clean it up.
s.doCleanup = true
// Set the Volume ID in the state.
ui.Message(fmt.Sprintf("Volume ID: %s", volume.ID))
state.Put("volume_id", volume.ID)
s.volumeID = volume.ID
return multistep.ActionContinue
}
func (s *StepCreateVolume) Cleanup(state multistep.StateBag) {
if !s.doCleanup {
return
}
config := state.Get("config").(*Config)
ui := state.Get("ui").(packersdk.Ui)
blockStorageClient, err := config.blockStorageV3Client()
if err != nil {
ui.Error(fmt.Sprintf(
"Error cleaning up volume. Please delete the volume manually: %s", s.volumeID))
return
}
// Wait for volume to become available.
status, err := GetVolumeStatus(blockStorageClient, s.volumeID)
if err != nil {
ui.Error(fmt.Sprintf(
"Error getting the volume information. Please delete the volume manually: %s", s.volumeID))
return
}
if status != "available" {
ui.Say(fmt.Sprintf(
"Waiting for volume %s (volume id: %s) to become available...", s.VolumeName, s.volumeID))
if err := WaitForVolume(blockStorageClient, s.volumeID); err != nil {
ui.Error(fmt.Sprintf(
"Error getting the volume information. Please delete the volume manually: %s", s.volumeID))
return
}
}
ui.Say(fmt.Sprintf("Deleting volume: %s ...", s.volumeID))
err = volumes.Delete(blockStorageClient, s.volumeID, volumes.DeleteOpts{}).ExtractErr()
if err != nil {
ui.Error(fmt.Sprintf(
"Error cleaning up volume. Please delete the volume manually: %s", s.volumeID))
}
}
|