vsphere/virtual_machine_config_structure.go
func expandExtraConfig(d *schema.ResourceData) []types.BaseOptionValue {
	if d.HasChange("extra_config") {
		// While there's a possibility that modification of some settings in
		// extraConfig may not require a restart, there's no real way for us to
		// know, hence we just default to requiring a reboot here.
		d.Set("reboot_required", true)
	} else {
		// There's no change here, so we might as well just return a nil set, which
		// is a no-op for modification of extraConfig.
		return nil
	}
	var opts []types.BaseOptionValue

	// Nil out removed values
	old, new := d.GetChange("extra_config")
	for k1 := range old.(map[string]interface{}) {
		var found bool
		for k2 := range new.(map[string]interface{}) {
			if k1 == k2 {
				found = true
			}
		}
		if !found {
			ov := &types.OptionValue{
				Key:   k1,
				Value: "",
			}
			opts = append(opts, ov)
		}
	}

	// Look for new values, in addition to changed values.
	for k1, v1 := range new.(map[string]interface{}) {
		var found bool
		for k2, v2 := range old.(map[string]interface{}) {
			if k1 == k2 {
				found = true
				if v1 != v2 {
					// Value has changed, add it to the changeset
					ov := &types.OptionValue{
						Key:   k1,
						Value: types.AnyType(v1),
					}
					opts = append(opts, ov)
				}
			}
		}
		if !found {
			// Brand new value
			ov := &types.OptionValue{
				Key:   k1,
				Value: types.AnyType(v1),
			}
			opts = append(opts, ov)
		}
	}

	// Done!
	return opts
}
func expandExtraConfig(d *schema.ResourceData) []types.BaseOptionValue {
	if d.HasChange("extra_config") {
		// While there's a possibility that modification of some settings in
		// extraConfig may not require a restart, there's no real way for us to
		// know, hence we just default to requiring a reboot here.
		d.Set("reboot_required", true)
	} else {
		// There's no change here, so we might as well just return a nil set, which
		// is a no-op for modification of extraConfig.
		return nil
	}
	var opts []types.BaseOptionValue

	// Nil out removed values
	old, new := d.GetChange("extra_config")
	for k1 := range old.(map[string]interface{}) {
		var found bool
		for k2 := range new.(map[string]interface{}) {
			if k1 == k2 {
				found = true
			}
		}
		if !found {
			ov := &types.OptionValue{
				Key:   k1,
				Value: "",
			}
			opts = append(opts, ov)
		}
	}

	// Look for new values, in addition to changed values.
	for k1, v1 := range new.(map[string]interface{}) {
		var found bool
		for k2, v2 := range old.(map[string]interface{}) {
			if k1 == k2 {
				found = true
				if v1 != v2 {
					// Value has changed, add it to the changeset
					ov := &types.OptionValue{
						Key:   k1,
						Value: types.AnyType(v1),
					}
					opts = append(opts, ov)
				}
			}
		}
		if !found {
			// Brand new value
			ov := &types.OptionValue{
				Key:   k1,
				Value: types.AnyType(v1),
			}
			opts = append(opts, ov)
		}
	}

	// Done!
	return opts
}
// expandExtraConfig reads in all the extra_config key/value pairs and returns
// the appropriate OptionValue slice.
//
// We track changes to keys to determine if any have been removed from
// configuration - if they have, we add them with a nil value to ensure they
// are removed from extraConfig on the update.