add step customize and docs
This commit is contained in:
parent
943cb1275d
commit
c6e9bde97b
|
@ -54,6 +54,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
},
|
||||
)
|
||||
|
||||
if b.config.CustomizeConfig != nil {
|
||||
steps = append(steps, &StepCustomize{
|
||||
Config: b.config.CustomizeConfig,
|
||||
})
|
||||
}
|
||||
|
||||
if b.config.Comm.Type != "none" {
|
||||
steps = append(steps,
|
||||
&common.StepHTTPIPDiscover{
|
||||
|
|
|
@ -40,6 +40,8 @@ type Config struct {
|
|||
// The VM template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified.
|
||||
// The import doesn't work if [convert_to_template](#convert_to_template) is set to true.
|
||||
ContentLibraryDestinationConfig *common.ContentLibraryDestinationConfig `mapstructure:"content_library_destination"`
|
||||
// Customize the cloned VM to configure host, network, or licensing settings. See the [customization options](#customization).
|
||||
CustomizeConfig *CustomizeConfig `mapstructure:"customize"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -75,6 +77,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
|||
if c.ContentLibraryDestinationConfig != nil {
|
||||
errs = packer.MultiErrorAppend(errs, c.ContentLibraryDestinationConfig.Prepare(&c.LocationConfig)...)
|
||||
}
|
||||
if c.CustomizeConfig != nil {
|
||||
errs = packer.MultiErrorAppend(errs, c.CustomizeConfig.Prepare()...)
|
||||
}
|
||||
|
||||
if len(errs.Errors) > 0 {
|
||||
return nil, errs
|
||||
|
|
|
@ -118,6 +118,7 @@ type FlatConfig struct {
|
|||
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template" hcl:"convert_to_template"`
|
||||
Export *common.FlatExportConfig `mapstructure:"export" cty:"export" hcl:"export"`
|
||||
ContentLibraryDestinationConfig *common.FlatContentLibraryDestinationConfig `mapstructure:"content_library_destination" cty:"content_library_destination" hcl:"content_library_destination"`
|
||||
CustomizeConfig *FlatCustomizeConfig `mapstructure:"customize" cty:"customize" hcl:"customize"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
|
@ -240,6 +241,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false},
|
||||
"export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())},
|
||||
"content_library_destination": &hcldec.BlockSpec{TypeName: "content_library_destination", Nested: hcldec.ObjectSpec((*common.FlatContentLibraryDestinationConfig)(nil).HCL2Spec())},
|
||||
"customize": &hcldec.BlockSpec{TypeName: "customize", Nested: hcldec.ObjectSpec((*FlatCustomizeConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type CustomizeConfig,LinuxOptions,NetworkInterfaces,NetworkInterface,GlobalDnsSettings,GlobalRoutingSettings
|
||||
package clone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// A cloned virtual machine can be [customized](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-58E346FF-83AE-42B8-BE58-253641D257BC.html)
|
||||
// to configure host, network, or licensing settings.
|
||||
//
|
||||
// To perform virtual machine customization as a part of the clone process, specify the customize block with the
|
||||
// respective customization options. Windows guests are customized using Sysprep, which will result in the machine SID being reset.
|
||||
// Before using customization, check that your source VM meets the [requirements](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-E63B6FAA-8D35-428D-B40C-744769845906.html)
|
||||
// for guest OS customization on vSphere.
|
||||
// See the [customization example](#customization-example) for a usage synopsis.
|
||||
//
|
||||
// The settings for customize are as follows:
|
||||
type CustomizeConfig struct {
|
||||
// Settings to Linux guest OS customization. See [Linux customization settings](#linux-customization-settings).
|
||||
LinuxOptions *LinuxOptions `mapstructure:"linux_options"`
|
||||
// Supply your own sysprep.xml file to allow full control of the customization process out-of-band of vSphere.
|
||||
WindowsSysPrepFile string `mapstructure:"windows_sysprep_file"`
|
||||
// Configure network interfaces on a per-interface basis that should matched up to the network adapters present in the VM.
|
||||
// To use DHCP, declare an empty network_interface for each adapter being configured. This field is required.
|
||||
// See [Network interface settings](#network-interface-settings).
|
||||
NetworkInterfaces NetworkInterfaces `mapstructure:"network_interface"`
|
||||
GlobalRoutingSettings `mapstructure:",squash"`
|
||||
GlobalDnsSettings `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
type LinuxOptions struct {
|
||||
// The domain name for this machine. This, along with [host_name](#host_name), make up the FQDN of this virtual machine.
|
||||
Domain string `mapstructure:"domain"`
|
||||
// The host name for this machine. This, along with [domain](#domain), make up the FQDN of this virtual machine.
|
||||
Hostname string `mapstructure:"host_name"`
|
||||
// Tells the operating system that the hardware clock is set to UTC. Default: true.
|
||||
HWClockUTC config.Trilean `mapstructure:"hw_clock_utc"`
|
||||
// Sets the time zone. The default is UTC.
|
||||
Timezone string `mapstructure:"time_zone"`
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
// Network interface-specific DNS server settings for Windows operating systems.
|
||||
// Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section.
|
||||
DnsServerList []string `mapstructure:"dns_server_list"`
|
||||
// Network interface-specific DNS search domain for Windows operating systems.
|
||||
// Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section.
|
||||
DnsDomain string `mapstructure:"dns_domain"`
|
||||
// The IPv4 address assigned to this network adapter. If left blank or not included, DHCP is used.
|
||||
Ipv4Address string `mapstructure:"ipv4_address"`
|
||||
// The IPv4 subnet mask, in bits (example: 24 for 255.255.255.0).
|
||||
Ipv4NetMask int `mapstructure:"ipv4_netmask"`
|
||||
// The IPv6 address assigned to this network adapter. If left blank or not included, auto-configuration is used.
|
||||
Ipv6Address string `mapstructure:"ipv6_address"`
|
||||
// The IPv6 subnet mask, in bits (example: 32).
|
||||
Ipv6NetMask int `mapstructure:"ipv6_netmask"`
|
||||
}
|
||||
|
||||
type NetworkInterfaces []NetworkInterface
|
||||
|
||||
// The settings here must match the IP/mask of at least one network_interface supplied to customization.
|
||||
type GlobalRoutingSettings struct {
|
||||
// The IPv4 default gateway when using network_interface customization on the virtual machine.
|
||||
Ipv4Gateway string `mapstructure:"ipv4_gateway"`
|
||||
// The IPv6 default gateway when using network_interface customization on the virtual machine.
|
||||
Ipv6Gateway string `mapstructure:"ipv6_gateway"`
|
||||
}
|
||||
|
||||
// The following settings configure DNS globally, generally for Linux systems. For Windows systems,
|
||||
// this is done per-interface, see [network interface](#network_interface) settings.
|
||||
type GlobalDnsSettings struct {
|
||||
// The list of DNS servers to configure on a virtual machine.
|
||||
DnsServerList []string `mapstructure:"dns_server_list"`
|
||||
// A list of DNS search domains to add to the DNS configuration on the virtual machine.
|
||||
DnsSuffixList []string `mapstructure:"dns_suffix_list"`
|
||||
}
|
||||
|
||||
type StepCustomize struct {
|
||||
Config *CustomizeConfig
|
||||
}
|
||||
|
||||
func (c *CustomizeConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
if c.LinuxOptions == nil && c.WindowsSysPrepFile == "" {
|
||||
errs = append(errs, fmt.Errorf("customize is empty"))
|
||||
}
|
||||
if c.LinuxOptions != nil && c.WindowsSysPrepFile != "" {
|
||||
errs = append(errs, fmt.Errorf("`linux_options` and `windows_sysprep_text` both set - one must not be included if the other is specified"))
|
||||
}
|
||||
|
||||
if c.LinuxOptions != nil {
|
||||
if c.LinuxOptions.Hostname == "" {
|
||||
errs = append(errs, fmt.Errorf("linux options `host_name` is empty"))
|
||||
}
|
||||
if c.LinuxOptions.Domain == "" {
|
||||
errs = append(errs, fmt.Errorf("linux options `domain` is empty"))
|
||||
}
|
||||
|
||||
if c.LinuxOptions.HWClockUTC == config.TriUnset {
|
||||
c.LinuxOptions.HWClockUTC = config.TriTrue
|
||||
}
|
||||
if c.LinuxOptions.Timezone == "" {
|
||||
c.LinuxOptions.Timezone = "UTC"
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.NetworkInterfaces) == 0 {
|
||||
errs = append(errs, fmt.Errorf("one or more `network_interface` must be provided"))
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func (s *StepCustomize) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
identity, err := s.identitySettings()
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
nicSettingsMap := s.nicSettingsMap()
|
||||
globalIpSettings := s.globalIpSettings()
|
||||
|
||||
spec := types.CustomizationSpec{
|
||||
Identity: identity,
|
||||
NicSettingMap: nicSettingsMap,
|
||||
GlobalIPSettings: globalIpSettings,
|
||||
}
|
||||
ui.Say("Customizing VM...")
|
||||
err = vm.Customize(spec)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCustomize) identitySettings() (types.BaseCustomizationIdentitySettings, error) {
|
||||
if s.Config.LinuxOptions != nil {
|
||||
return &types.CustomizationLinuxPrep{
|
||||
HostName: &types.CustomizationFixedName{
|
||||
Name: s.Config.LinuxOptions.Hostname,
|
||||
},
|
||||
Domain: s.Config.LinuxOptions.Domain,
|
||||
TimeZone: s.Config.LinuxOptions.Timezone,
|
||||
HwClockUTC: s.Config.LinuxOptions.HWClockUTC.ToBoolPointer(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if s.Config.WindowsSysPrepFile != "" {
|
||||
sysPrep, err := ioutil.ReadFile(s.Config.WindowsSysPrepFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error on reading %s: %s", s.Config.WindowsSysPrepFile, err)
|
||||
}
|
||||
return &types.CustomizationSysprepText{
|
||||
Value: string(sysPrep),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no customization identity found")
|
||||
}
|
||||
|
||||
func (s *StepCustomize) nicSettingsMap() []types.CustomizationAdapterMapping {
|
||||
result := make([]types.CustomizationAdapterMapping, len(s.Config.NetworkInterfaces))
|
||||
var ipv4gwFound, ipv6gwFound bool
|
||||
for i := range s.Config.NetworkInterfaces {
|
||||
var adapter types.CustomizationIPSettings
|
||||
adapter, ipv4gwFound, ipv6gwFound = s.ipSettings(i, !ipv4gwFound, !ipv6gwFound)
|
||||
obj := types.CustomizationAdapterMapping{
|
||||
Adapter: adapter,
|
||||
}
|
||||
result[i] = obj
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *StepCustomize) ipSettings(n int, ipv4gwAdd bool, ipv6gwAdd bool) (types.CustomizationIPSettings, bool, bool) {
|
||||
var v4gwFound, v6gwFound bool
|
||||
var obj types.CustomizationIPSettings
|
||||
|
||||
ipv4Address := s.Config.NetworkInterfaces[n].Ipv4Address
|
||||
if ipv4Address != "" {
|
||||
ipv4mask := s.Config.NetworkInterfaces[n].Ipv4NetMask
|
||||
ipv4Gateway := s.Config.Ipv4Gateway
|
||||
obj.Ip = &types.CustomizationFixedIp{
|
||||
IpAddress: ipv4Address,
|
||||
}
|
||||
obj.SubnetMask = v4CIDRMaskToDotted(ipv4mask)
|
||||
// Check for the gateway
|
||||
if ipv4gwAdd && ipv4Gateway != "" && matchGateway(ipv4Address, ipv4mask, ipv4Gateway) {
|
||||
obj.Gateway = []string{ipv4Gateway}
|
||||
v4gwFound = true
|
||||
}
|
||||
} else {
|
||||
obj.Ip = &types.CustomizationDhcpIpGenerator{}
|
||||
}
|
||||
|
||||
obj.DnsServerList = s.Config.NetworkInterfaces[n].DnsServerList
|
||||
obj.DnsDomain = s.Config.NetworkInterfaces[n].DnsDomain
|
||||
obj.IpV6Spec, v6gwFound = s.IPSettingsIPV6Address(n, ipv6gwAdd)
|
||||
|
||||
return obj, v4gwFound, v6gwFound
|
||||
}
|
||||
|
||||
func v4CIDRMaskToDotted(mask int) string {
|
||||
m := net.CIDRMask(mask, 32)
|
||||
a := int(m[0])
|
||||
b := int(m[1])
|
||||
c := int(m[2])
|
||||
d := int(m[3])
|
||||
return fmt.Sprintf("%d.%d.%d.%d", a, b, c, d)
|
||||
}
|
||||
|
||||
func (s *StepCustomize) IPSettingsIPV6Address(n int, gwAdd bool) (*types.CustomizationIPSettingsIpV6AddressSpec, bool) {
|
||||
addr := s.Config.NetworkInterfaces[n].Ipv6Address
|
||||
var gwFound bool
|
||||
if addr == "" {
|
||||
return nil, gwFound
|
||||
}
|
||||
mask := s.Config.NetworkInterfaces[n].Ipv6NetMask
|
||||
gw := s.Config.Ipv6Gateway
|
||||
obj := &types.CustomizationIPSettingsIpV6AddressSpec{
|
||||
Ip: []types.BaseCustomizationIpV6Generator{
|
||||
&types.CustomizationFixedIpV6{
|
||||
IpAddress: addr,
|
||||
SubnetMask: int32(mask),
|
||||
},
|
||||
},
|
||||
}
|
||||
if gwAdd && gw != "" && matchGateway(addr, mask, gw) {
|
||||
obj.Gateway = []string{gw}
|
||||
gwFound = true
|
||||
}
|
||||
return obj, gwFound
|
||||
}
|
||||
|
||||
// matchGateway take an IP, mask, and gateway, and checks to see if the gateway
|
||||
// is reachable from the IP address.
|
||||
func matchGateway(a string, m int, g string) bool {
|
||||
ip := net.ParseIP(a)
|
||||
gw := net.ParseIP(g)
|
||||
var mask net.IPMask
|
||||
if ip.To4() != nil {
|
||||
mask = net.CIDRMask(m, 32)
|
||||
} else {
|
||||
mask = net.CIDRMask(m, 128)
|
||||
}
|
||||
if ip.Mask(mask).Equal(gw.Mask(mask)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *StepCustomize) globalIpSettings() types.CustomizationGlobalIPSettings {
|
||||
return types.CustomizationGlobalIPSettings{
|
||||
DnsServerList: s.Config.DnsServerList,
|
||||
DnsSuffixList: s.Config.DnsSuffixList,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepCustomize) Cleanup(_ multistep.StateBag) {}
|
|
@ -0,0 +1,154 @@
|
|||
// Code generated by "mapstructure-to-hcl2 -type CustomizeConfig,LinuxOptions,NetworkInterfaces,NetworkInterface,GlobalDnsSettings,GlobalRoutingSettings"; DO NOT EDIT.
|
||||
package clone
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatCustomizeConfig is an auto-generated flat version of CustomizeConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatCustomizeConfig struct {
|
||||
LinuxOptions *FlatLinuxOptions `mapstructure:"linux_options" cty:"linux_options" hcl:"linux_options"`
|
||||
WindowsSysPrepFile *string `mapstructure:"windows_sysprep_file" cty:"windows_sysprep_file" hcl:"windows_sysprep_file"`
|
||||
NetworkInterfaces []FlatNetworkInterface `mapstructure:"network_interface" cty:"network_interface" hcl:"network_interface"`
|
||||
Ipv4Gateway *string `mapstructure:"ipv4_gateway" cty:"ipv4_gateway" hcl:"ipv4_gateway"`
|
||||
Ipv6Gateway *string `mapstructure:"ipv6_gateway" cty:"ipv6_gateway" hcl:"ipv6_gateway"`
|
||||
DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"`
|
||||
DnsSuffixList []string `mapstructure:"dns_suffix_list" cty:"dns_suffix_list" hcl:"dns_suffix_list"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatCustomizeConfig.
|
||||
// FlatCustomizeConfig is an auto-generated flat version of CustomizeConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*CustomizeConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatCustomizeConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a CustomizeConfig.
|
||||
// This spec is used by HCL to read the fields of CustomizeConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatCustomizeConfig.
|
||||
func (*FlatCustomizeConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"linux_options": &hcldec.BlockSpec{TypeName: "linux_options", Nested: hcldec.ObjectSpec((*FlatLinuxOptions)(nil).HCL2Spec())},
|
||||
"windows_sysprep_file": &hcldec.AttrSpec{Name: "windows_sysprep_file", Type: cty.String, Required: false},
|
||||
"network_interface": &hcldec.BlockListSpec{TypeName: "network_interface", Nested: hcldec.ObjectSpec((*FlatNetworkInterface)(nil).HCL2Spec())},
|
||||
"ipv4_gateway": &hcldec.AttrSpec{Name: "ipv4_gateway", Type: cty.String, Required: false},
|
||||
"ipv6_gateway": &hcldec.AttrSpec{Name: "ipv6_gateway", Type: cty.String, Required: false},
|
||||
"dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false},
|
||||
"dns_suffix_list": &hcldec.AttrSpec{Name: "dns_suffix_list", Type: cty.List(cty.String), Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatGlobalDnsSettings is an auto-generated flat version of GlobalDnsSettings.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatGlobalDnsSettings struct {
|
||||
DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"`
|
||||
DnsSuffixList []string `mapstructure:"dns_suffix_list" cty:"dns_suffix_list" hcl:"dns_suffix_list"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatGlobalDnsSettings.
|
||||
// FlatGlobalDnsSettings is an auto-generated flat version of GlobalDnsSettings.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*GlobalDnsSettings) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatGlobalDnsSettings)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a GlobalDnsSettings.
|
||||
// This spec is used by HCL to read the fields of GlobalDnsSettings.
|
||||
// The decoded values from this spec will then be applied to a FlatGlobalDnsSettings.
|
||||
func (*FlatGlobalDnsSettings) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false},
|
||||
"dns_suffix_list": &hcldec.AttrSpec{Name: "dns_suffix_list", Type: cty.List(cty.String), Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatGlobalRoutingSettings is an auto-generated flat version of GlobalRoutingSettings.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatGlobalRoutingSettings struct {
|
||||
Ipv4Gateway *string `mapstructure:"ipv4_gateway" cty:"ipv4_gateway" hcl:"ipv4_gateway"`
|
||||
Ipv6Gateway *string `mapstructure:"ipv6_gateway" cty:"ipv6_gateway" hcl:"ipv6_gateway"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatGlobalRoutingSettings.
|
||||
// FlatGlobalRoutingSettings is an auto-generated flat version of GlobalRoutingSettings.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*GlobalRoutingSettings) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatGlobalRoutingSettings)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a GlobalRoutingSettings.
|
||||
// This spec is used by HCL to read the fields of GlobalRoutingSettings.
|
||||
// The decoded values from this spec will then be applied to a FlatGlobalRoutingSettings.
|
||||
func (*FlatGlobalRoutingSettings) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"ipv4_gateway": &hcldec.AttrSpec{Name: "ipv4_gateway", Type: cty.String, Required: false},
|
||||
"ipv6_gateway": &hcldec.AttrSpec{Name: "ipv6_gateway", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatLinuxOptions is an auto-generated flat version of LinuxOptions.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatLinuxOptions struct {
|
||||
Domain *string `mapstructure:"domain" cty:"domain" hcl:"domain"`
|
||||
Hostname *string `mapstructure:"host_name" cty:"host_name" hcl:"host_name"`
|
||||
HWClockUTC *bool `mapstructure:"hw_clock_utc" cty:"hw_clock_utc" hcl:"hw_clock_utc"`
|
||||
Timezone *string `mapstructure:"time_zone" cty:"time_zone" hcl:"time_zone"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatLinuxOptions.
|
||||
// FlatLinuxOptions is an auto-generated flat version of LinuxOptions.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*LinuxOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatLinuxOptions)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a LinuxOptions.
|
||||
// This spec is used by HCL to read the fields of LinuxOptions.
|
||||
// The decoded values from this spec will then be applied to a FlatLinuxOptions.
|
||||
func (*FlatLinuxOptions) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"domain": &hcldec.AttrSpec{Name: "domain", Type: cty.String, Required: false},
|
||||
"host_name": &hcldec.AttrSpec{Name: "host_name", Type: cty.String, Required: false},
|
||||
"hw_clock_utc": &hcldec.AttrSpec{Name: "hw_clock_utc", Type: cty.Bool, Required: false},
|
||||
"time_zone": &hcldec.AttrSpec{Name: "time_zone", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatNetworkInterface is an auto-generated flat version of NetworkInterface.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatNetworkInterface struct {
|
||||
DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"`
|
||||
DnsDomain *string `mapstructure:"dns_domain" cty:"dns_domain" hcl:"dns_domain"`
|
||||
Ipv4Address *string `mapstructure:"ipv4_address" cty:"ipv4_address" hcl:"ipv4_address"`
|
||||
Ipv4NetMask *int `mapstructure:"ipv4_netmask" cty:"ipv4_netmask" hcl:"ipv4_netmask"`
|
||||
Ipv6Address *string `mapstructure:"ipv6_address" cty:"ipv6_address" hcl:"ipv6_address"`
|
||||
Ipv6NetMask *int `mapstructure:"ipv6_netmask" cty:"ipv6_netmask" hcl:"ipv6_netmask"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatNetworkInterface.
|
||||
// FlatNetworkInterface is an auto-generated flat version of NetworkInterface.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*NetworkInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatNetworkInterface)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a NetworkInterface.
|
||||
// This spec is used by HCL to read the fields of NetworkInterface.
|
||||
// The decoded values from this spec will then be applied to a FlatNetworkInterface.
|
||||
func (*FlatNetworkInterface) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false},
|
||||
"dns_domain": &hcldec.AttrSpec{Name: "dns_domain", Type: cty.String, Required: false},
|
||||
"ipv4_address": &hcldec.AttrSpec{Name: "ipv4_address", Type: cty.String, Required: false},
|
||||
"ipv4_netmask": &hcldec.AttrSpec{Name: "ipv4_netmask", Type: cty.Number, Required: false},
|
||||
"ipv6_address": &hcldec.AttrSpec{Name: "ipv6_address", Type: cty.String, Required: false},
|
||||
"ipv6_netmask": &hcldec.AttrSpec{Name: "ipv6_netmask", Type: cty.Number, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -524,6 +524,14 @@ func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) Customize(spec types.CustomizationSpec) error {
|
||||
task, err := vm.vm.Customize(vm.driver.ctx, spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.Wait(vm.driver.ctx)
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) ResizeDisk(diskSize int64) error {
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
|
||||
|
|
|
@ -86,6 +86,70 @@ can be done via environment variable:
|
|||
|
||||
@include 'builder/vsphere/common/ConfigParamsConfig-not-required.mdx'
|
||||
|
||||
### Customization
|
||||
|
||||
@include '/builder/vsphere/clone/CustomizeConfig.mdx'
|
||||
|
||||
@include 'builder/vsphere/clone/CustomizeConfig-not-required.mdx'
|
||||
|
||||
#### Network Interface Settings
|
||||
|
||||
@include 'builder/vsphere/clone/NetworkInterface-not-required.mdx'
|
||||
|
||||
#### Global Routing Settings
|
||||
|
||||
@include 'builder/vsphere/clone/GlobalRoutingSettings.mdx'
|
||||
|
||||
@include 'builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx'
|
||||
|
||||
#### Global DNS Settings
|
||||
|
||||
@include 'builder/vsphere/clone/GlobalDnsSettings.mdx'
|
||||
|
||||
@include 'builder/vsphere/clone/GlobalDnsSettings-not-required.mdx'
|
||||
|
||||
#### Linux Customization Settings
|
||||
|
||||
@include 'builder/vsphere/clone/LinuxOptions-not-required.mdx'
|
||||
|
||||
#### Customization Example
|
||||
|
||||
<Tabs>
|
||||
<Tab heading="JSON">
|
||||
|
||||
```json
|
||||
"customize": {
|
||||
"linux_options": {
|
||||
"host_name": "packer-test",
|
||||
"domain": "test.internal"
|
||||
},
|
||||
"network_interface": {
|
||||
"ipv4_address": "10.0.0.10",
|
||||
"ipv4_netmask": "24"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab heading="HCL2">
|
||||
|
||||
```hcl
|
||||
customize {
|
||||
linux_options {
|
||||
host_name = "packer-test"
|
||||
domain = "test.internal"
|
||||
}
|
||||
|
||||
network_interface {
|
||||
ipv4_address = "10.0.0.10"
|
||||
ipv4_netmask = "24"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Boot configuration
|
||||
|
||||
@include 'common/bootcommand/BootConfig.mdx'
|
||||
|
|
|
@ -11,3 +11,5 @@
|
|||
- `content_library_destination` (\*common.ContentLibraryDestinationConfig) - Configuration for importing the VM template to a Content Library.
|
||||
The VM template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified.
|
||||
The import doesn't work if [convert_to_template](#convert_to_template) is set to true.
|
||||
|
||||
- `customize` (\*CustomizeConfig) - Customize the cloned VM to configure host, network, or licensing settings. See the [customization options](#customization).
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!-- Code generated from the comments of the CustomizeConfig struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `linux_options` (\*LinuxOptions) - Settings to Linux guest OS customization. See [Linux customization settings](#linux-customization-settings).
|
||||
|
||||
- `windows_sysprep_file` (string) - Supply your own sysprep.xml file to allow full control of the customization process out-of-band of vSphere.
|
||||
|
||||
- `network_interface` (NetworkInterfaces) - Configure network interfaces on a per-interface basis that should matched up to the network adapters present in the VM.
|
||||
To use DHCP, declare an empty network_interface for each adapter being configured. This field is required.
|
||||
See [Network interface settings](#network-interface-settings).
|
|
@ -0,0 +1,12 @@
|
|||
<!-- Code generated from the comments of the CustomizeConfig struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
A cloned virtual machine can be [customized](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-58E346FF-83AE-42B8-BE58-253641D257BC.html)
|
||||
to configure host, network, or licensing settings.
|
||||
|
||||
To perform virtual machine customization as a part of the clone process, specify the customize block with the
|
||||
respective customization options. Windows guests are customized using Sysprep, which will result in the machine SID being reset.
|
||||
Before using customization, check that your source VM meets the [requirements](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-E63B6FAA-8D35-428D-B40C-744769845906.html)
|
||||
for guest OS customization on vSphere.
|
||||
See the [customization example](#customization-example) for a usage synopsis.
|
||||
|
||||
The settings for customize are as follows:
|
|
@ -0,0 +1,5 @@
|
|||
<!-- Code generated from the comments of the GlobalDnsSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `dns_server_list` ([]string) - The list of DNS servers to configure on a virtual machine.
|
||||
|
||||
- `dns_suffix_list` ([]string) - A list of DNS search domains to add to the DNS configuration on the virtual machine.
|
|
@ -0,0 +1,4 @@
|
|||
<!-- Code generated from the comments of the GlobalDnsSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
The following settings configure DNS globally, generally for Linux systems. For Windows systems,
|
||||
this is done per-interface, see [network interface](#network_interface) settings.
|
|
@ -0,0 +1,5 @@
|
|||
<!-- Code generated from the comments of the GlobalRoutingSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `ipv4_gateway` (string) - The IPv4 default gateway when using network_interface customization on the virtual machine.
|
||||
|
||||
- `ipv6_gateway` (string) - The IPv6 default gateway when using network_interface customization on the virtual machine.
|
|
@ -0,0 +1,3 @@
|
|||
<!-- Code generated from the comments of the GlobalRoutingSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
The settings here must match the IP/mask of at least one network_interface supplied to customization.
|
|
@ -0,0 +1,9 @@
|
|||
<!-- Code generated from the comments of the LinuxOptions struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `domain` (string) - The domain name for this machine. This, along with [host_name](#host_name), make up the FQDN of this virtual machine.
|
||||
|
||||
- `host_name` (string) - The host name for this machine. This, along with [domain](#domain), make up the FQDN of this virtual machine.
|
||||
|
||||
- `hw_clock_utc` (boolean) - Tells the operating system that the hardware clock is set to UTC. Default: true.
|
||||
|
||||
- `time_zone` (string) - Sets the time zone. The default is UTC.
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Code generated from the comments of the NetworkInterface struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `dns_server_list` ([]string) - Network interface-specific DNS server settings for Windows operating systems.
|
||||
Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section.
|
||||
|
||||
- `dns_domain` (string) - Network interface-specific DNS search domain for Windows operating systems.
|
||||
Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section.
|
||||
|
||||
- `ipv4_address` (string) - The IPv4 address assigned to this network adapter. If left blank or not included, DHCP is used.
|
||||
|
||||
- `ipv4_netmask` (int) - The IPv4 subnet mask, in bits (example: 24 for 255.255.255.0).
|
||||
|
||||
- `ipv6_address` (string) - The IPv6 address assigned to this network adapter. If left blank or not included, auto-configuration is used.
|
||||
|
||||
- `ipv6_netmask` (int) - The IPv6 subnet mask, in bits (example: 32).
|
Loading…
Reference in New Issue