Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,11 @@ vsi_user_data | string | Optional | User data to be made available when setting
vsi_boot_vol_capacity | string | Optional | The capacity to use for the volume (in gigabytes). Must be at least the image's minimum_provisioned_size. The maximum value may increase in the future.
vsi_boot_vol_profile | string | Optional | User can provide the available profile for the boot volume. Supported profiles: `general-purpose`, `5iops-tier`, `10iops-tier`, `sdp`, `custom`. Refer https://cloud.ibm.com/docs/vpc?topic=vpc-block-storage-profiles&interface=ui for profile info. Requires `vsi_boot_vol_capacity` to be set, except when creating from a snapshot (`vsi_boot_snapshot_id`), where the restored volume inherits the snapshot's size if no capacity is given. Cannot be combined with `vsi_boot_volume_id` (an existing volume keeps its own profile).
vsi_boot_vol_iops | number | Optional | The maximum I/O operations per second (IOPS) for the boot volume. Only honored when `vsi_boot_vol_profile` is `custom` or `sdp`; the tiered profiles derive IOPS from capacity. Must be within the chosen profile's range for the volume size (enforced by IBM Cloud). Cannot be combined with `vsi_boot_volume_id`.
vsi_boot_vol_bandwidth | number | Optional | The maximum bandwidth (in megabits per second) for the boot volume. Only honored when `vsi_boot_vol_profile` is `custom` or `sdp`. If unset, IBM Cloud assigns a default for the profile. Cannot be combined with `vsi_boot_volume_id`.
vsi_boot_vol_bandwidth | number | Optional | The maximum bandwidth (in megabits per second) for the boot volume. Only honored when `vsi_boot_vol_profile` is `sdp`. If unset, IBM Cloud assigns a default for the profile. Cannot be combined with `vsi_boot_volume_id`.
vsi_data_vol_capacity | number | Optional | Capacity (in gigabytes, 10–32000) of an ephemeral scratch data volume attached to the builder instance. The volume is created with the instance and deleted with it, and is **never part of the captured image** (the image is captured from the boot volume only). Use it to keep large transient build artifacts — package/module caches, downloads, build trees — off the boot volume so they are not exported at image-capture time. Mount it in a provisioner (the disk appears as an unformatted block device) and point your cache/build directories at it; if you do not mount it and redirect writes to it, it has no effect on the captured image. If unset, no data volume is attached.
vsi_data_vol_profile | string | Optional | Profile for the data volume. Supported profiles: `general-purpose`, `5iops-tier`, `10iops-tier`, `sdp`, `custom`. Requires `vsi_data_vol_capacity` to be set. Defaults to `general-purpose`.
vsi_data_vol_iops | number | Optional | The maximum I/O operations per second (IOPS) for the data volume. Only honored when `vsi_data_vol_profile` is `custom` or `sdp`; the tiered profiles derive IOPS from capacity. Must be within the chosen profile's range for the volume size (enforced by IBM Cloud).
vsi_data_vol_bandwidth | number | Optional | The maximum bandwidth (in megabits per second) for the data volume. Only honored when `vsi_data_vol_profile` is `sdp`. If unset, IBM Cloud assigns a default for the profile.
image_name | string | Optional | The name of the resulting custom image that will appear in your account. Required.
encryption_key_crn | string | Optional | The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Services Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.
communicator | string | Required | Communicators are the mechanism Packer uses to upload files, execute scripts, etc. with the machine being created. Choose between "ssh" (for Linux) and "winrm" (for Windows). Required.
Expand Down
49 changes: 43 additions & 6 deletions builder/ibmcloud/vpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ type Config struct {
VSIBootBandwidth int `mapstructure:"vsi_boot_vol_bandwidth"`
VSIBootVolumeID string `mapstructure:"vsi_boot_volume_id"`
VSIBootSnapshotID string `mapstructure:"vsi_boot_snapshot_id"`
VSIDataCapacity int `mapstructure:"vsi_data_vol_capacity"`
VSIDataProfile string `mapstructure:"vsi_data_vol_profile"`
VSIDataIops int `mapstructure:"vsi_data_vol_iops"`
VSIDataBandwidth int `mapstructure:"vsi_data_vol_bandwidth"`
VSIProfile string `mapstructure:"vsi_profile"`
VSIInterface string `mapstructure:"vsi_interface"`
VSIUserDataFile string `mapstructure:"vsi_user_data_file"`
Expand Down Expand Up @@ -123,12 +127,14 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
if c.VSIBootProfile != "" && !slices.Contains(allowedBootProfiles, c.VSIBootProfile) {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_boot_vol_profile must be one of: general-purpose, 5iops-tier, 10iops-tier, sdp, custom"))
}
// iops/bandwidth are only honored by the custom and sdp profiles; the tiered
// profiles derive them from capacity. This validation is the single source of
// truth for that rule (the bootVolumePrototype helpers do not re-enforce it).
customOrSdp := c.VSIBootProfile == "custom" || c.VSIBootProfile == "sdp"
if (c.VSIBootIops != 0 || c.VSIBootBandwidth != 0) && !customOrSdp {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_boot_vol_iops/vsi_boot_vol_bandwidth require vsi_boot_vol_profile to be 'custom' or 'sdp'"))
// iops is honored by the custom and sdp profiles; bandwidth only by sdp; the
// tiered profiles derive both from capacity. This validation is the single
// source of truth for that rule (the bootVolumePrototype helpers do not re-enforce it).
if c.VSIBootIops != 0 && c.VSIBootProfile != "custom" && c.VSIBootProfile != "sdp" {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_boot_vol_iops requires vsi_boot_vol_profile to be 'custom' or 'sdp'"))
}
if c.VSIBootBandwidth != 0 && c.VSIBootProfile != "sdp" {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_boot_vol_bandwidth requires vsi_boot_vol_profile to be 'sdp'"))
}
bootVolumeTuned := c.VSIBootProfile != "" || c.VSIBootIops != 0 || c.VSIBootBandwidth != 0
// The by-image and catalog-offering paths only attach a boot volume (and thus
Expand All @@ -149,6 +155,37 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_boot_vol_iops and vsi_boot_vol_bandwidth must not be negative"))
}

// Data-volume validation mirrors the boot-volume rules above. The data volume
// is an ephemeral scratch disk attached to the builder VSI and deleted with it
// (DeleteVolumeOnInstanceDelete); it never enters the captured image, which is
// taken from the boot volume only. It lets a build keep large transient writes
// (build caches, downloads) off the boot volume so they are not exported at
// capture time.
if c.VSIDataCapacity != 0 && (c.VSIDataCapacity < 10 || c.VSIDataCapacity > 32000) {
errs = packer.MultiErrorAppend(errs, errors.New("data capacity out of bound: provide a valid capacity between 10 and 32000"))
}
allowedDataProfiles := []string{"general-purpose", "5iops-tier", "10iops-tier", "sdp", "custom"}
if c.VSIDataProfile != "" && !slices.Contains(allowedDataProfiles, c.VSIDataProfile) {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_data_vol_profile must be one of: general-purpose, 5iops-tier, 10iops-tier, sdp, custom"))
}
// iops is honored by the custom and sdp profiles; bandwidth only by sdp. The
// tiered profiles derive both from capacity, same rule as the boot volume above.
if c.VSIDataIops != 0 && c.VSIDataProfile != "custom" && c.VSIDataProfile != "sdp" {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_data_vol_iops requires vsi_data_vol_profile to be 'custom' or 'sdp'"))
}
if c.VSIDataBandwidth != 0 && c.VSIDataProfile != "sdp" {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_data_vol_bandwidth requires vsi_data_vol_profile to be 'sdp'"))
}
// The data volume is attached only when a capacity is set; without it the
// profile/iops/bandwidth would be silently dropped, so require capacity.
dataVolumeTuned := c.VSIDataProfile != "" || c.VSIDataIops != 0 || c.VSIDataBandwidth != 0
if dataVolumeTuned && c.VSIDataCapacity == 0 {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_data_vol_profile/vsi_data_vol_iops/vsi_data_vol_bandwidth require vsi_data_vol_capacity to be set"))
}
if c.VSIDataIops < 0 || c.VSIDataBandwidth < 0 {
errs = packer.MultiErrorAppend(errs, errors.New("vsi_data_vol_iops and vsi_data_vol_bandwidth must not be negative"))
}

var oneOfInput int // validation for mutually exclusive fields.

if c.VSIBaseImageID != "" {
Expand Down
8 changes: 8 additions & 0 deletions builder/ibmcloud/vpc/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading