mirror of https://github.com/hashicorp/packer
Merge pull request #10287 from hashicorp/implement_9990
Add configuration options to add additional storage to a cloned vmpull/10290/head
commit
60e62bbb51
@ -0,0 +1,118 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type StorageConfig,DiskConfig
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Defines the disk storage for a VM.
|
||||
//
|
||||
// Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 20000,
|
||||
// "disk_thin_provisioned": true
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 20000
|
||||
// disk_thin_provisioned = true
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Example that creates 2 pvscsi controllers and adds 2 disks to each one:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "disk_controller_type": ["pvscsi", "pvscsi"],
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
//
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// disk_controller_type = ["pvscsi", "pvscsi"]
|
||||
// storage {
|
||||
// disk_size = 15000,
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// ```
|
||||
type DiskConfig struct {
|
||||
// The size of the disk in MB.
|
||||
DiskSize int64 `mapstructure:"disk_size" required:"true"`
|
||||
// Enable VMDK thin provisioning for VM. Defaults to `false`.
|
||||
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
|
||||
// Enable VMDK eager scrubbing for VM. Defaults to `false`.
|
||||
DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"`
|
||||
// The assigned disk controller. Defaults to the first one (0)
|
||||
DiskControllerIndex int `mapstructure:"disk_controller_index"`
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
// Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
// Defaults to `lsilogic`. See
|
||||
// [SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
// for additional details.
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type"`
|
||||
// Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration).
|
||||
Storage []DiskConfig `mapstructure:"storage"`
|
||||
}
|
||||
|
||||
func (c *StorageConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
if len(c.Storage) > 0 {
|
||||
for i, storage := range c.Storage {
|
||||
if storage.DiskSize == 0 {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_size' is required", i))
|
||||
}
|
||||
if storage.DiskControllerIndex >= len(c.DiskControllerType) {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_controller_index' references an unknown disk controller", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type StorageConfig,DiskConfig"; DO NOT EDIT.
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatDiskConfig struct {
|
||||
DiskSize *int64 `mapstructure:"disk_size" required:"true" cty:"disk_size" hcl:"disk_size"`
|
||||
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned" hcl:"disk_thin_provisioned"`
|
||||
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub" hcl:"disk_eagerly_scrub"`
|
||||
DiskControllerIndex *int `mapstructure:"disk_controller_index" cty:"disk_controller_index" hcl:"disk_controller_index"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatDiskConfig.
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*DiskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatDiskConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a DiskConfig.
|
||||
// This spec is used by HCL to read the fields of DiskConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatDiskConfig.
|
||||
func (*FlatDiskConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
|
||||
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
|
||||
"disk_controller_index": &hcldec.AttrSpec{Name: "disk_controller_index", Type: cty.Number, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatStorageConfig is an auto-generated flat version of StorageConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatStorageConfig struct {
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatStorageConfig.
|
||||
// FlatStorageConfig is an auto-generated flat version of StorageConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*StorageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatStorageConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a StorageConfig.
|
||||
// This spec is used by HCL to read the fields of StorageConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatStorageConfig.
|
||||
func (*FlatStorageConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Disk struct {
|
||||
DiskSize int64
|
||||
DiskEagerlyScrub bool
|
||||
DiskThinProvisioned bool
|
||||
ControllerIndex int
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
DiskControllerType []string // example: "scsi", "pvscsi", "nvme", "lsilogic"
|
||||
Storage []Disk
|
||||
}
|
||||
|
||||
func (c *StorageConfig) AddStorageDevices(existingDevices object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
|
||||
newDevices := object.VirtualDeviceList{}
|
||||
|
||||
// Create new controller based on existing devices list and add it to the new devices list
|
||||
// to confirm creation
|
||||
var controllers []types.BaseVirtualController
|
||||
for _, controllerType := range c.DiskControllerType {
|
||||
var device types.BaseVirtualDevice
|
||||
var err error
|
||||
if controllerType == "nvme" {
|
||||
device, err = existingDevices.CreateNVMEController()
|
||||
} else {
|
||||
device, err = existingDevices.CreateSCSIController(controllerType)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingDevices = append(existingDevices, device)
|
||||
newDevices = append(newDevices, device)
|
||||
controller, err := existingDevices.FindDiskController(existingDevices.Name(device))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
controllers = append(controllers, controller)
|
||||
}
|
||||
|
||||
for _, dc := range c.Storage {
|
||||
disk := &types.VirtualDisk{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
Key: existingDevices.NewKey(),
|
||||
Backing: &types.VirtualDiskFlatVer2BackingInfo{
|
||||
DiskMode: string(types.VirtualDiskModePersistent),
|
||||
ThinProvisioned: types.NewBool(dc.DiskThinProvisioned),
|
||||
EagerlyScrub: types.NewBool(dc.DiskEagerlyScrub),
|
||||
},
|
||||
},
|
||||
CapacityInKB: dc.DiskSize * 1024,
|
||||
}
|
||||
|
||||
existingDevices.AssignController(disk, controllers[dc.ControllerIndex])
|
||||
newDevices = append(newDevices, disk)
|
||||
}
|
||||
|
||||
return newDevices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
}
|
||||
|
||||
func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) {
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(disks) {
|
||||
case 0:
|
||||
return nil, errors.New("VM has no disks")
|
||||
case 1:
|
||||
return disks[0], nil
|
||||
}
|
||||
return nil, errors.New("VM has multiple disks")
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_thin_provisioned` (bool) - Enable VMDK thin provisioning for VM. Defaults to `false`.
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_size` (int64) - The size of the disk in MB.
|
||||
@ -1,4 +1,4 @@
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
Defines the disk storage for a VM.
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
<!-- Code generated from the comments of the StorageConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_controller_type` ([]string) - Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
Defaults to `lsilogic`. See
|
||||
[SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
for additional details.
|
||||
|
||||
- `storage` ([]DiskConfig) - Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration).
|
||||
Loading…
Reference in new issue