File: step_create_volume.go

package info (click to toggle)
packer 1.6.6%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 33,156 kB
  • sloc: sh: 1,154; python: 619; makefile: 251; ruby: 205; xml: 97
file content (134 lines) | stat: -rw-r--r-- 4,001 bytes parent folder | download | duplicates (2)
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))
	}
}