vsphere/internal/virtualdevice/virtual_machine_disk_subresource.go
func (r *DiskSubresource) DiffGeneral() error {
	log.Printf("[DEBUG] %s: Beginning diff validation", r)
	name, err := diskLabelOrName(r.data)
	if err != nil {
		return err
	}

	// Enforce the maximum unit number, which is the current value of
	// scsi_controller_count * 15 - 1.
	ctlrCount := r.rdd.Get("scsi_controller_count").(int)
	maxUnit := ctlrCount*15 - 1
	currentUnit := r.Get("unit_number").(int)
	if currentUnit > maxUnit {
		return fmt.Errorf("unit_number on disk %q too high (%d) - maximum value is %d with %d SCSI controller(s)", name, currentUnit, maxUnit, ctlrCount)
	}

	if r.Get("attach").(bool) {
		switch {
		case r.Get("datastore_id").(string) == "":
			return fmt.Errorf("datastore_id for disk %q is required when attach is set", name)
		case r.Get("size").(int) > 0:
			return fmt.Errorf("size for disk %q cannot be defined when attach is set", name)
		case r.Get("eagerly_scrub").(bool):
			return fmt.Errorf("eagerly_scrub for disk %q cannot be defined when attach is set", name)
		case r.Get("keep_on_remove").(bool):
			return fmt.Errorf("keep_on_remove for disk %q is implicit when attach is set, please remove this setting", name)
		}
	} else {
		// Enforce size as a required field when attach is not set
		if r.Get("size").(int) < 1 {
			return fmt.Errorf("size for disk %q: required option not set", name)
		}
	}
	// Block certain options from being set depending on the vSphere version.
	version := viapi.ParseVersionFromClient(r.client)
	if r.Get("disk_sharing").(string) != string(types.VirtualDiskSharingSharingNone) {
		if version.Older(viapi.VSphereVersion{Product: version.Product, Major: 6}) {
			return fmt.Errorf("multi-writer disk_sharing is only supported on vSphere 6 and higher")
		}
	}
	// Prevent eagerly_scrub and thin_provisioned from both being set to true. A
	// thin_provisioned disk cannot be eagerly scrubbed since it would then be
	// allocating the entire disk.
	if r.Get("eagerly_scrub").(bool) && r.Get("thin_provisioned").(bool) {
		return fmt.Errorf("%s: eagerly_scrub and thin_provisioned cannot both be set to true", name)
	}
	log.Printf("[DEBUG] %s: Diff validation complete", r)
	return nil
}
func (r *DiskSubresource) DiffGeneral() error {
	log.Printf("[DEBUG] %s: Beginning diff validation", r)
	name, err := diskLabelOrName(r.data)
	if err != nil {
		return err
	}

	// Enforce the maximum unit number, which is the current value of
	// scsi_controller_count * 15 - 1.
	ctlrCount := r.rdd.Get("scsi_controller_count").(int)
	maxUnit := ctlrCount*15 - 1
	currentUnit := r.Get("unit_number").(int)
	if currentUnit > maxUnit {
		return fmt.Errorf("unit_number on disk %q too high (%d) - maximum value is %d with %d SCSI controller(s)", name, currentUnit, maxUnit, ctlrCount)
	}

	if r.Get("attach").(bool) {
		switch {
		case r.Get("datastore_id").(string) == "":
			return fmt.Errorf("datastore_id for disk %q is required when attach is set", name)
		case r.Get("size").(int) > 0:
			return fmt.Errorf("size for disk %q cannot be defined when attach is set", name)
		case r.Get("eagerly_scrub").(bool):
			return fmt.Errorf("eagerly_scrub for disk %q cannot be defined when attach is set", name)
		case r.Get("keep_on_remove").(bool):
			return fmt.Errorf("keep_on_remove for disk %q is implicit when attach is set, please remove this setting", name)
		}
	} else {
		// Enforce size as a required field when attach is not set
		if r.Get("size").(int) < 1 {
			return fmt.Errorf("size for disk %q: required option not set", name)
		}
	}
	// Block certain options from being set depending on the vSphere version.
	version := viapi.ParseVersionFromClient(r.client)
	if r.Get("disk_sharing").(string) != string(types.VirtualDiskSharingSharingNone) {
		if version.Older(viapi.VSphereVersion{Product: version.Product, Major: 6}) {
			return fmt.Errorf("multi-writer disk_sharing is only supported on vSphere 6 and higher")
		}
	}
	// Prevent eagerly_scrub and thin_provisioned from both being set to true. A
	// thin_provisioned disk cannot be eagerly scrubbed since it would then be
	// allocating the entire disk.
	if r.Get("eagerly_scrub").(bool) && r.Get("thin_provisioned").(bool) {
		return fmt.Errorf("%s: eagerly_scrub and thin_provisioned cannot both be set to true", name)
	}
	log.Printf("[DEBUG] %s: Diff validation complete", r)
	return nil
}
// DiffGeneral performs complex validation of an individual disk sub-resource
// that can't be done in schema alone. Should be run on new and existing disks.