Add content_library_destination to import VM template to a Content Library (#9551)

This commit is contained in:
Sylvia Moss 2020-07-10 11:01:10 +02:00 committed by GitHub
parent 61b79b6e53
commit 9c1409dbba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2341 additions and 231 deletions

View File

@ -104,6 +104,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
},
)
if b.config.ContentLibraryDestinationConfig != nil {
steps = append(steps, &common.StepImportToContentLibrary{
ContentLibConfig: b.config.ContentLibraryDestinationConfig,
})
}
if b.config.Export != nil {
steps = append(steps, &common.StepExport{
Name: b.config.Export.Name,

View File

@ -33,8 +33,13 @@ type Config struct {
CreateSnapshot bool `mapstructure:"create_snapshot"`
// Convert VM to a template. Defaults to `false`.
ConvertToTemplate bool `mapstructure:"convert_to_template"`
// Configuration for exporting VM to an ovf file.
// The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
Export *common.ExportConfig `mapstructure:"export"`
// 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.
ContentLibraryDestinationConfig *common.ContentLibraryDestinationConfig `mapstructure:"content_library_destination"`
ctx interpolate.Context
}
@ -67,6 +72,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
if c.Export != nil {
errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...)
}
if c.ContentLibraryDestinationConfig != nil {
errs = packer.MultiErrorAppend(errs, c.ContentLibraryDestinationConfig.Prepare(&c.LocationConfig)...)
}
if len(errs.Errors) > 0 {
return nil, errs

View File

@ -10,109 +10,110 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"`
Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"`
Template *string `mapstructure:"template" cty:"template" hcl:"template"`
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"`
Network *string `mapstructure:"network" cty:"network" hcl:"network"`
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
Host *string `mapstructure:"host" cty:"host" hcl:"host"`
ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"`
Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"`
SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"`
CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"`
CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"`
CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"`
CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"`
CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"`
RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"`
RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"`
RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"`
MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"`
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"`
Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"`
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"`
SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"`
WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"`
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template" hcl:"convert_to_template"`
Export *common.FlatExportConfig `mapstructure:"export" cty:"export" hcl:"export"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"`
Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"`
Template *string `mapstructure:"template" cty:"template" hcl:"template"`
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"`
Network *string `mapstructure:"network" cty:"network" hcl:"network"`
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
Host *string `mapstructure:"host" cty:"host" hcl:"host"`
ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"`
Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"`
SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"`
CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"`
CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"`
CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"`
CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"`
CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"`
RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"`
RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"`
RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"`
MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"`
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"`
Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"`
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"`
SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"`
WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"`
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"`
}
// FlatMapstructure returns a new FlatConfig.
@ -230,6 +231,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
"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())},
}
return s
}

View File

@ -44,8 +44,8 @@ type StepConnect struct {
Config *ConnectConfig
}
func (s *StepConnect) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
d, err := driver.NewDriver(&driver.ConnectConfig{
func (s *StepConnect) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
d, err := driver.NewDriver(ctx, &driver.ConnectConfig{
VCenterServer: s.Config.VCenterServer,
Username: s.Config.Username,
Password: s.Config.Password,

View File

@ -0,0 +1,127 @@
//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type ContentLibraryDestinationConfig
package common
import (
"context"
"fmt"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/vmware/govmomi/vapi/vcenter"
)
// With this configuration Packer creates a library item in a content library whose content is a virtual machine template created from the just built VM.
// The virtual machine template is stored in a newly created library item.
type ContentLibraryDestinationConfig struct {
// Name of the library in which the new library item containing the VM template should be created.
// The Content Library should be of type Local to allow deploying virtual machines.
Library string `mapstructure:"library"`
// Name of the library item that will be created. The name of the item should be different from [vm_name](#vm_name).
// Defaults to [vm_name](#vm_name) + timestamp.
Name string `mapstructure:"name"`
// Description of the library item that will be created. Defaults to "Packer imported [vm_name](#vm_name) VM template".
Description string `mapstructure:"description"`
// Cluster onto which the virtual machine template should be placed.
// If cluster and resource_pool are both specified, resource_pool must belong to cluster.
// If cluster and host are both specified, host must be a member of cluster.
// Defaults to [cluster](#cluster).
Cluster string `mapstructure:"cluster"`
// Virtual machine folder into which the virtual machine template should be placed.
// Defaults to the same folder as the source virtual machine.
Folder string `mapstructure:"folder"`
// Host onto which the virtual machine template should be placed.
// If host and resource_pool are both specified, resource_pool must belong to host.
// If host and cluster are both specified, host must be a member of cluster.
// Defaults to [host](#host).
Host string `mapstructure:"host"`
// Resource pool into which the virtual machine template should be placed.
// Defaults to [resource_pool](#resource_pool). if [resource_pool](#resource_pool) is also unset,
// the system will attempt to choose a suitable resource pool for the virtual machine template.
ResourcePool string `mapstructure:"resource_pool"`
// The datastore for the virtual machine template's configuration and log files.
// Defaults to the storage backing associated with the library specified by library.
Datastore string `mapstructure:"datastore"`
}
func (c *ContentLibraryDestinationConfig) Prepare(lc *LocationConfig) []error {
var errs *packer.MultiError
if c.Library == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("a library name must be provided"))
}
if c.Name == lc.VMName {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("the content library destination name must be different from the VM name"))
}
if c.Name == "" {
// Add timestamp to the the name to differentiate from the original VM
// otherwise vSphere won't be able to create the template which will be imported
name, err := interpolate.Render(lc.VMName+"{{timestamp}}", nil)
if err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("unable to parse content library VM template name: %s", err))
}
c.Name = name
}
if c.Cluster == "" {
c.Cluster = lc.Cluster
}
if c.Host == "" {
c.Host = lc.Host
}
if c.ResourcePool == "" {
c.ResourcePool = lc.ResourcePool
}
if c.Description == "" {
c.Description = fmt.Sprintf("Packer imported %s VM template", lc.VMName)
}
if errs != nil && len(errs.Errors) > 0 {
return errs.Errors
}
return nil
}
type StepImportToContentLibrary struct {
ContentLibConfig *ContentLibraryDestinationConfig
}
func (s *StepImportToContentLibrary) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
template := vcenter.Template{
Name: s.ContentLibConfig.Name,
Description: s.ContentLibConfig.Description,
Library: s.ContentLibConfig.Library,
Placement: &vcenter.Placement{
Cluster: s.ContentLibConfig.Cluster,
Folder: s.ContentLibConfig.Folder,
Host: s.ContentLibConfig.Host,
ResourcePool: s.ContentLibConfig.ResourcePool,
},
}
if s.ContentLibConfig.Datastore != "" {
template.VMHomeStorage = &vcenter.DiskStorage{
Datastore: s.ContentLibConfig.Datastore,
}
}
ui.Say(fmt.Sprintf("Importing VM template %s to Content Library...", s.ContentLibConfig.Name))
err := vm.ImportToContentLibrary(template)
if err != nil {
ui.Error(fmt.Sprintf("Failed to import VM template %s: %s", s.ContentLibConfig.Name, err.Error()))
state.Put("error", err)
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *StepImportToContentLibrary) Cleanup(multistep.StateBag) {
}

View File

@ -0,0 +1,44 @@
// Code generated by "mapstructure-to-hcl2 -type ContentLibraryDestinationConfig"; DO NOT EDIT.
package common
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
)
// FlatContentLibraryDestinationConfig is an auto-generated flat version of ContentLibraryDestinationConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatContentLibraryDestinationConfig struct {
Library *string `mapstructure:"library" cty:"library" hcl:"library"`
Name *string `mapstructure:"name" cty:"name" hcl:"name"`
Description *string `mapstructure:"description" cty:"description" hcl:"description"`
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
Host *string `mapstructure:"host" cty:"host" hcl:"host"`
ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"`
Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"`
}
// FlatMapstructure returns a new FlatContentLibraryDestinationConfig.
// FlatContentLibraryDestinationConfig is an auto-generated flat version of ContentLibraryDestinationConfig.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*ContentLibraryDestinationConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatContentLibraryDestinationConfig)
}
// HCL2Spec returns the hcl spec of a ContentLibraryDestinationConfig.
// This spec is used by HCL to read the fields of ContentLibraryDestinationConfig.
// The decoded values from this spec will then be applied to a FlatContentLibraryDestinationConfig.
func (*FlatContentLibraryDestinationConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"library": &hcldec.AttrSpec{Name: "library", Type: cty.String, Required: false},
"name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false},
"description": &hcldec.AttrSpec{Name: "description", Type: cty.String, Required: false},
"cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false},
"folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false},
"host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false},
"resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false},
"datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false},
}
return s
}

View File

@ -1,6 +1,7 @@
package testing
import (
"context"
"encoding/json"
"fmt"
"math/rand"
@ -44,7 +45,7 @@ func TestConn(t *testing.T) *driver.Driver {
password = "jetbrains"
}
d, err := driver.NewDriver(&driver.ConnectConfig{
d, err := driver.NewDriver(context.TODO(), &driver.ConnectConfig{
VCenterServer: "vcenter.vsphere65.test",
Username: username,
Password: password,

View File

@ -0,0 +1,19 @@
package driver
import "github.com/vmware/govmomi/object"
type Cluster struct {
driver *Driver
cluster *object.ClusterComputeResource
}
func (d *Driver) FindCluster(name string) (*Cluster, error) {
c, err := d.finder.ClusterComputeResource(d.ctx, name)
if err != nil {
return nil, err
}
return &Cluster{
cluster: c,
driver: d,
}, nil
}

View File

@ -10,6 +10,7 @@ import (
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
@ -17,6 +18,7 @@ import (
type Driver struct {
ctx context.Context
client *govmomi.Client
restClient *rest.Client
finder *find.Finder
datacenter *object.Datacenter
}
@ -29,9 +31,7 @@ type ConnectConfig struct {
Datacenter string
}
func NewDriver(config *ConnectConfig) (*Driver, error) {
ctx := context.TODO()
func NewDriver(ctx context.Context, config *ConnectConfig) (*Driver, error) {
vcenterUrl, err := url.Parse(fmt.Sprintf("https://%v/sdk", config.VCenterServer))
if err != nil {
return nil, err
@ -56,6 +56,12 @@ func NewDriver(config *ConnectConfig) (*Driver, error) {
return nil, err
}
restClient := rest.NewClient(vimClient)
err = restClient.Login(ctx, credentials)
if err != nil {
return nil, err
}
finder := find.NewFinder(client.Client, false)
datacenter, err := finder.DatacenterOrDefault(ctx, config.Datacenter)
if err != nil {
@ -66,6 +72,7 @@ func NewDriver(config *ConnectConfig) (*Driver, error) {
d := Driver{
ctx: ctx,
client: client,
restClient: restClient,
datacenter: datacenter,
finder: finder,
}

View File

@ -1,6 +1,7 @@
package driver
import (
"context"
"fmt"
"math/rand"
"os"
@ -21,7 +22,7 @@ func newTestDriver(t *testing.T) *Driver {
password = "jetbrains"
}
d, err := NewDriver(&ConnectConfig{
d, err := NewDriver(context.TODO(), &ConnectConfig{
VCenterServer: "vcenter.vsphere65.test",
Username: username,
Password: password,

View File

@ -0,0 +1,20 @@
package driver
import "github.com/vmware/govmomi/vapi/library"
type Library struct {
driver *Driver
library *library.Library
}
func (d *Driver) FindContentLibrary(name string) (*Library, error) {
lm := library.NewManager(d.restClient)
l, err := lm.GetLibraryByName(d.ctx, name)
if err != nil {
return nil, err
}
return &Library{
library: l,
driver: d,
}, nil
}

View File

@ -11,12 +11,12 @@ import (
"time"
"github.com/hashicorp/packer/packer"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/nfc"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vapi/vcenter"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
@ -667,6 +667,60 @@ func (vm *VirtualMachine) ConvertToTemplate() error {
return vm.vm.MarkAsTemplate(vm.driver.ctx)
}
func (vm *VirtualMachine) ImportToContentLibrary(template vcenter.Template) error {
template.SourceVM = vm.vm.Reference().Value
l, err := vm.driver.FindContentLibrary(template.Library)
if err != nil {
return err
}
if l.library.Type != "LOCAL" {
return fmt.Errorf("can not deploy a VM to the content library %s of type %s; the content library must be of type LOCAL", template.Library, l.library.Type)
}
template.Library = l.library.ID
if template.Placement.Cluster != "" {
c, err := vm.driver.FindCluster(template.Placement.Cluster)
if err != nil {
return err
}
template.Placement.Cluster = c.cluster.Reference().Value
}
if template.Placement.Folder != "" {
f, err := vm.driver.FindFolder(template.Placement.Folder)
if err != nil {
return err
}
template.Placement.Folder = f.folder.Reference().Value
}
if template.Placement.Host != "" {
h, err := vm.driver.FindHost(template.Placement.Host)
if err != nil {
return err
}
template.Placement.Host = h.host.Reference().Value
}
if template.Placement.ResourcePool != "" {
rp, err := vm.driver.FindResourcePool(template.Placement.Cluster, template.Placement.Host, template.Placement.ResourcePool)
if err != nil {
return err
}
template.Placement.ResourcePool = rp.pool.Reference().Value
}
if template.VMHomeStorage != nil {
d, err := vm.driver.FindDatastore(template.VMHomeStorage.Datastore, template.Placement.Host)
if err != nil {
return err
}
template.VMHomeStorage.Datastore = d.ds.Reference().Value
}
vcm := vcenter.NewManager(vm.driver.restClient)
_, err = vcm.CreateTemplate(vm.driver.ctx, template)
return err
}
func (vm *VirtualMachine) GetDir() (string, error) {
vmInfo, err := vm.Info("name", "layoutEx.file")
if err != nil {

View File

@ -1,13 +1,14 @@
package main
import (
"context"
"fmt"
"github.com/hashicorp/packer/builder/vsphere/driver"
)
func main() {
d, err := driver.NewDriver(&driver.ConnectConfig{
d, err := driver.NewDriver(context.TODO(), &driver.ConnectConfig{
VCenterServer: "vcenter.vsphere65.test",
Username: "root",
Password: "jetbrains",

View File

@ -145,6 +145,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
},
)
if b.config.ContentLibraryDestinationConfig != nil {
steps = append(steps, &common.StepImportToContentLibrary{
ContentLibConfig: b.config.ContentLibraryDestinationConfig,
})
}
if b.config.Export != nil {
steps = append(steps, &common.StepExport{
Name: b.config.Export.Name,

View File

@ -42,6 +42,10 @@ type Config struct {
// Configuration for exporting VM to an ovf file.
// The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
Export *common.ExportConfig `mapstructure:"export"`
// 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.
ContentLibraryDestinationConfig *common.ContentLibraryDestinationConfig `mapstructure:"content_library_destination"`
ctx interpolate.Context
}
@ -83,6 +87,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
if c.Export != nil {
errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...)
}
if c.ContentLibraryDestinationConfig != nil {
errs = packer.MultiErrorAppend(errs, c.ContentLibraryDestinationConfig.Prepare(&c.LocationConfig)...)
}
if len(errs.Errors) > 0 {
return warnings, errs

View File

@ -10,122 +10,123 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"`
Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"`
Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"`
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"`
Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"`
DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
USBController *bool `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"`
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
Host *string `mapstructure:"host" cty:"host" hcl:"host"`
ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"`
Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"`
SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"`
CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"`
CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"`
CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"`
CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"`
CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"`
RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"`
RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"`
RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"`
MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"`
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"`
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"`
ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"`
RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"`
FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"`
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"`
FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"`
SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"`
WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"`
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template" hcl:"convert_to_template"`
Export *common.FlatExportConfig `mapstructure:"export" cty:"export" hcl:"export"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"`
Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"`
Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"`
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"`
Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"`
DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
USBController *bool `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"`
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
Host *string `mapstructure:"host" cty:"host" hcl:"host"`
ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"`
Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"`
SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"`
CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"`
CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"`
CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"`
CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"`
CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"`
RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"`
RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"`
RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"`
MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"`
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"`
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"`
ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"`
RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"`
FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"`
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"`
FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"`
SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"`
WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"`
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"`
}
// FlatMapstructure returns a new FlatConfig.
@ -256,6 +257,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
"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())},
}
return s
}

View File

@ -42,6 +42,7 @@ func (s *StepRemoveFloppy) Run(_ context.Context, state multistep.StateBag) mult
state.Put("error", err)
return multistep.ActionHalt
}
state.Remove("uploaded_floppy_path")
}
return multistep.ActionContinue

View File

@ -35,6 +35,8 @@ func (p *HCL2PostProcessor) HCL2Prepare(buildVars map[string]interface{}) error
switch v := v.(type) {
case string:
buildValues[k] = cty.StringVal(v)
case int64:
buildValues[k] = cty.NumberIntVal(v)
default:
return fmt.Errorf("unhandled buildvar type: %T", v)
}

View File

@ -3,7 +3,6 @@ package hcl2template
import (
"context"
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/packer"
@ -35,6 +34,8 @@ func (p *HCL2Provisioner) HCL2Prepare(buildVars map[string]interface{}) error {
switch v := v.(type) {
case string:
buildValues[k] = cty.StringVal(v)
case int64:
buildValues[k] = cty.NumberIntVal(v)
default:
return fmt.Errorf("unhandled buildvar type: %T", v)
}

View File

@ -10,6 +10,7 @@ type StateBag interface {
Get(string) interface{}
GetOk(string) (interface{}, bool)
Put(string, interface{})
Remove(string)
}
// BasicStateBag implements StateBag by using a normal map underneath
@ -45,3 +46,7 @@ func (b *BasicStateBag) Put(k string, v interface{}) {
// Write the data
b.data[k] = v
}
func (b *BasicStateBag) Remove(k string) {
delete(b.data, k)
}

View File

@ -0,0 +1,71 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
// VAPI REST Paths
const (
SessionPath = "/com/vmware/cis/session"
CategoryPath = "/com/vmware/cis/tagging/category"
TagPath = "/com/vmware/cis/tagging/tag"
AssociationPath = "/com/vmware/cis/tagging/tag-association"
LibraryPath = "/com/vmware/content/library"
LibraryItemFileData = "/com/vmware/cis/data"
LibraryItemPath = "/com/vmware/content/library/item"
LibraryItemFilePath = "/com/vmware/content/library/item/file"
LibraryItemUpdateSession = "/com/vmware/content/library/item/update-session"
LibraryItemUpdateSessionFile = "/com/vmware/content/library/item/updatesession/file"
LibraryItemDownloadSession = "/com/vmware/content/library/item/download-session"
LibraryItemDownloadSessionFile = "/com/vmware/content/library/item/downloadsession/file"
LocalLibraryPath = "/com/vmware/content/local-library"
SubscribedLibraryPath = "/com/vmware/content/subscribed-library"
SubscribedLibraryItem = "/com/vmware/content/library/subscribed-item"
VCenterOVFLibraryItem = "/com/vmware/vcenter/ovf/library-item"
VCenterVMTXLibraryItem = "/vcenter/vm-template/library-items"
VCenterVM = "/vcenter/vm"
SessionCookieName = "vmware-api-session-id"
)
// AssociatedObject is the same structure as types.ManagedObjectReference,
// just with a different field name (ID instead of Value).
// In the API we use mo.Reference, this type is only used for wire transfer.
type AssociatedObject struct {
Type string `json:"type"`
Value string `json:"id"`
}
// Reference implements mo.Reference
func (o AssociatedObject) Reference() types.ManagedObjectReference {
return types.ManagedObjectReference(o)
}
// Association for tag-association requests.
type Association struct {
ObjectID *AssociatedObject `json:"object_id,omitempty"`
}
// NewAssociation returns an Association, converting ref to an AssociatedObject.
func NewAssociation(ref mo.Reference) Association {
obj := AssociatedObject(ref.Reference())
return Association{
ObjectID: &obj,
}
}

View File

@ -0,0 +1,206 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
)
// StorageBackings for Content Libraries
type StorageBackings struct {
DatastoreID string `json:"datastore_id,omitempty"`
Type string `json:"type,omitempty"`
}
// Library provides methods to create, read, update, delete, and enumerate libraries.
type Library struct {
CreationTime *time.Time `json:"creation_time,omitempty"`
Description string `json:"description,omitempty"`
ID string `json:"id,omitempty"`
LastModifiedTime *time.Time `json:"last_modified_time,omitempty"`
LastSyncTime *time.Time `json:"last_sync_time,omitempty"`
Name string `json:"name,omitempty"`
Storage []StorageBackings `json:"storage_backings,omitempty"`
Type string `json:"type,omitempty"`
Version string `json:"version,omitempty"`
Subscription *Subscription `json:"subscription_info,omitempty"`
}
// Subscription info
type Subscription struct {
AuthenticationMethod string `json:"authentication_method"`
AutomaticSyncEnabled *bool `json:"automatic_sync_enabled,omitempty"`
OnDemand *bool `json:"on_demand,omitempty"`
Password string `json:"password,omitempty"`
SslThumbprint string `json:"ssl_thumbprint,omitempty"`
SubscriptionURL string `json:"subscription_url,omitempty"`
UserName string `json:"user_name,omitempty"`
}
// Patch merges updates from the given src.
func (l *Library) Patch(src *Library) {
if src.Name != "" {
l.Name = src.Name
}
if src.Description != "" {
l.Description = src.Description
}
if src.Version != "" {
l.Version = src.Version
}
}
// Manager extends rest.Client, adding content library related methods.
type Manager struct {
*rest.Client
}
// NewManager creates a new Manager instance with the given client.
func NewManager(client *rest.Client) *Manager {
return &Manager{
Client: client,
}
}
// Find is the search criteria for finding libraries.
type Find struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
}
// FindLibrary returns one or more libraries that match the provided search
// criteria.
//
// The provided name is case-insensitive.
//
// Either the name or type of library may be set to empty values in order
// to search for all libraries, all libraries with a specific name, regardless
// of type, or all libraries of a specified type.
func (c *Manager) FindLibrary(ctx context.Context, search Find) ([]string, error) {
url := c.Resource(internal.LibraryPath).WithAction("find")
spec := struct {
Spec Find `json:"spec"`
}{search}
var res []string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// CreateLibrary creates a new library with the given Type, Name,
// Description, and CategoryID.
func (c *Manager) CreateLibrary(ctx context.Context, library Library) (string, error) {
spec := struct {
Library Library `json:"create_spec"`
}{library}
path := internal.LocalLibraryPath
if library.Type == "SUBSCRIBED" {
path = internal.SubscribedLibraryPath
sub := library.Subscription
u, err := url.Parse(sub.SubscriptionURL)
if err != nil {
return "", err
}
if u.Scheme == "https" && sub.SslThumbprint == "" {
thumbprint := c.Thumbprint(u.Host)
if thumbprint == "" {
t := c.Transport.(*http.Transport)
if t.TLSClientConfig.InsecureSkipVerify {
var info object.HostCertificateInfo
_ = info.FromURL(u, t.TLSClientConfig)
thumbprint = info.ThumbprintSHA1
}
sub.SslThumbprint = thumbprint
}
}
}
url := c.Resource(path)
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// SyncLibrary syncs a subscribed library.
func (c *Manager) SyncLibrary(ctx context.Context, library *Library) error {
path := internal.SubscribedLibraryPath
url := c.Resource(path).WithID(library.ID).WithAction("sync")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// DeleteLibrary deletes an existing library.
func (c *Manager) DeleteLibrary(ctx context.Context, library *Library) error {
path := internal.LocalLibraryPath
if library.Type == "SUBSCRIBED" {
path = internal.SubscribedLibraryPath
}
url := c.Resource(path).WithID(library.ID)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// ListLibraries returns a list of all content library IDs in the system.
func (c *Manager) ListLibraries(ctx context.Context) ([]string, error) {
url := c.Resource(internal.LibraryPath)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// GetLibraryByID returns information on a library for the given ID.
func (c *Manager) GetLibraryByID(ctx context.Context, id string) (*Library, error) {
url := c.Resource(internal.LibraryPath).WithID(id)
var res Library
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// GetLibraryByName returns information on a library for the given name.
func (c *Manager) GetLibraryByName(ctx context.Context, name string) (*Library, error) {
// Lookup by name
libraries, err := c.GetLibraries(ctx)
if err != nil {
return nil, err
}
for i := range libraries {
if libraries[i].Name == name {
return &libraries[i], nil
}
}
return nil, fmt.Errorf("library name (%s) not found", name)
}
// GetLibraries returns a list of all content library details in the system.
func (c *Manager) GetLibraries(ctx context.Context) ([]Library, error) {
ids, err := c.ListLibraries(ctx)
if err != nil {
return nil, fmt.Errorf("get libraries failed for: %s", err)
}
var libraries []Library
for _, id := range ids {
library, err := c.GetLibraryByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("get library %s failed for %s", id, err)
}
libraries = append(libraries, *library)
}
return libraries, nil
}

View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"context"
"net/http"
"github.com/vmware/govmomi/vapi/internal"
)
// Checksum provides checksum information on library item files.
type Checksum struct {
Algorithm string `json:"algorithm,omitempty"`
Checksum string `json:"checksum"`
}
// File provides methods to get information on library item files.
type File struct {
Cached *bool `json:"cached,omitempty"`
Checksum *Checksum `json:"checksum_info,omitempty"`
Name string `json:"name,omitempty"`
Size *int64 `json:"size,omitempty"`
Version string `json:"version,omitempty"`
}
// ListLibraryItemFiles returns a list of all the files for a library item.
func (c *Manager) ListLibraryItemFiles(ctx context.Context, id string) ([]File, error) {
url := c.Resource(internal.LibraryItemFilePath).WithParam("library_item_id", id)
var res []File
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// GetLibraryItemFile returns a file with the provided name for a library item.
func (c *Manager) GetLibraryItemFile(ctx context.Context, id, fileName string) (*File, error) {
url := c.Resource(internal.LibraryItemFilePath).WithID(id).WithAction("get")
spec := struct {
Name string `json:"name"`
}{fileName}
var res File
return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}

View File

@ -0,0 +1,157 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"context"
"fmt"
"net/http"
"time"
"github.com/vmware/govmomi/vapi/internal"
)
const (
ItemTypeISO = "iso"
ItemTypeOVF = "ovf"
ItemTypeVMTX = "vm-template"
)
// Item provides methods to create, read, update, delete, and enumerate library items.
type Item struct {
Cached bool `json:"cached,omitempty"`
ContentVersion string `json:"content_version,omitempty"`
CreationTime *time.Time `json:"creation_time,omitempty"`
Description string `json:"description,omitempty"`
ID string `json:"id,omitempty"`
LastModifiedTime *time.Time `json:"last_modified_time,omitempty"`
LastSyncTime *time.Time `json:"last_sync_time,omitempty"`
LibraryID string `json:"library_id,omitempty"`
MetadataVersion string `json:"metadata_version,omitempty"`
Name string `json:"name,omitempty"`
Size int64 `json:"size,omitempty"`
SourceID string `json:"source_id,omitempty"`
Type string `json:"type,omitempty"`
Version string `json:"version,omitempty"`
}
// Patch merges updates from the given src.
func (i *Item) Patch(src *Item) {
if src.Name != "" {
i.Name = src.Name
}
if src.Description != "" {
i.Description = src.Description
}
if src.Type != "" {
i.Type = src.Type
}
if src.Version != "" {
i.Version = src.Version
}
}
// CreateLibraryItem creates a new library item
func (c *Manager) CreateLibraryItem(ctx context.Context, item Item) (string, error) {
type createItemSpec struct {
Name string `json:"name"`
Description string `json:"description"`
LibraryID string `json:"library_id,omitempty"`
Type string `json:"type"`
}
spec := struct {
Item createItemSpec `json:"create_spec"`
}{
Item: createItemSpec{
Name: item.Name,
Description: item.Description,
LibraryID: item.LibraryID,
Type: item.Type,
},
}
url := c.Resource(internal.LibraryItemPath)
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// SyncLibraryItem syncs a subscribed library item
func (c *Manager) SyncLibraryItem(ctx context.Context, item *Item, force bool) error {
body := struct {
Force bool `json:"force_sync_content"`
}{force}
url := c.Resource(internal.SubscribedLibraryItem).WithID(item.ID).WithAction("sync")
return c.Do(ctx, url.Request(http.MethodPost, body), nil)
}
// DeleteLibraryItem deletes an existing library item.
func (c *Manager) DeleteLibraryItem(ctx context.Context, item *Item) error {
url := c.Resource(internal.LibraryItemPath).WithID(item.ID)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// ListLibraryItems returns a list of all items in a content library.
func (c *Manager) ListLibraryItems(ctx context.Context, id string) ([]string, error) {
url := c.Resource(internal.LibraryItemPath).WithParam("library_id", id)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// GetLibraryItem returns information on a library item for the given ID.
func (c *Manager) GetLibraryItem(ctx context.Context, id string) (*Item, error) {
url := c.Resource(internal.LibraryItemPath).WithID(id)
var res Item
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// GetLibraryItems returns a list of all the library items for the specified library.
func (c *Manager) GetLibraryItems(ctx context.Context, libraryID string) ([]Item, error) {
ids, err := c.ListLibraryItems(ctx, libraryID)
if err != nil {
return nil, fmt.Errorf("get library items failed for: %s", err)
}
var items []Item
for _, id := range ids {
item, err := c.GetLibraryItem(ctx, id)
if err != nil {
return nil, fmt.Errorf("get library item for %s failed for %s", id, err)
}
items = append(items, *item)
}
return items, nil
}
// FindItem is the search criteria for finding library items.
type FindItem struct {
Cached *bool `json:"cached,omitempty"`
LibraryID string `json:"library_id,omitempty"`
Name string `json:"name,omitempty"`
SourceID string `json:"source_id,omitempty"`
Type string `json:"type,omitempty"`
}
// FindLibraryItems returns the IDs of all the library items that match the
// search criteria.
func (c *Manager) FindLibraryItems(
ctx context.Context, search FindItem) ([]string, error) {
url := c.Resource(internal.LibraryItemPath).WithAction("find")
spec := struct {
Spec FindItem `json:"spec"`
}{search}
var res []string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}

View File

@ -0,0 +1,71 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"context"
"net/http"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
)
// DownloadFile is the specification for the downloadsession
// operations file:add, file:get, and file:list.
type DownloadFile struct {
BytesTransferred int64 `json:"bytes_transferred"`
Checksum *Checksum `json:"checksum_info,omitempty"`
DownloadEndpoint *TransferEndpoint `json:"download_endpoint,omitempty"`
ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"`
Name string `json:"name"`
Size int64 `json:"size,omitempty"`
Status string `json:"status"`
}
// GetLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session.
func (c *Manager) GetLibraryItemDownloadSessionFile(ctx context.Context, sessionID string, name string) (*DownloadFile, error) {
url := c.Resource(internal.LibraryItemDownloadSessionFile).WithID(sessionID).WithAction("get")
spec := struct {
Name string `json:"file_name"`
}{name}
var res DownloadFile
err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
if err != nil {
return nil, err
}
if res.Status == "ERROR" {
return nil, res.ErrorMessage
}
return &res, nil
}
// ListLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session.
func (c *Manager) ListLibraryItemDownloadSessionFile(ctx context.Context, sessionID string) ([]DownloadFile, error) {
url := c.Resource(internal.LibraryItemDownloadSessionFile).WithParam("download_session_id", sessionID)
var res []DownloadFile
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// PrepareLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session.
func (c *Manager) PrepareLibraryItemDownloadSessionFile(ctx context.Context, sessionID string, name string) (*DownloadFile, error) {
url := c.Resource(internal.LibraryItemDownloadSessionFile).WithID(sessionID).WithAction("prepare")
spec := struct {
Name string `json:"file_name"`
}{name}
var res DownloadFile
return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}

View File

@ -0,0 +1,165 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"context"
"net/http"
"time"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
)
// Session is used to create an initial update or download session
type Session struct {
ClientProgress int64 `json:"client_progress,omitempty"`
ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"`
ExpirationTime *time.Time `json:"expiration_time,omitempty"`
ID string `json:"id,omitempty"`
LibraryItemContentVersion string `json:"library_item_content_version,omitempty"`
LibraryItemID string `json:"library_item_id,omitempty"`
State string `json:"state,omitempty"`
}
// CreateLibraryItemUpdateSession creates a new library item
func (c *Manager) CreateLibraryItemUpdateSession(ctx context.Context, session Session) (string, error) {
url := c.Resource(internal.LibraryItemUpdateSession)
spec := struct {
CreateSpec Session `json:"create_spec"`
}{session}
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// GetLibraryItemUpdateSession gets the update session information with status
func (c *Manager) GetLibraryItemUpdateSession(ctx context.Context, id string) (*Session, error) {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id)
var res Session
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// ListLibraryItemUpdateSession gets the list of update sessions
func (c *Manager) ListLibraryItemUpdateSession(ctx context.Context) ([]string, error) {
url := c.Resource(internal.LibraryItemUpdateSession)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// CancelLibraryItemUpdateSession cancels an update session
func (c *Manager) CancelLibraryItemUpdateSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("cancel")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// CompleteLibraryItemUpdateSession completes an update session
func (c *Manager) CompleteLibraryItemUpdateSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("complete")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// DeleteLibraryItemUpdateSession deletes an update session
func (c *Manager) DeleteLibraryItemUpdateSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// FailLibraryItemUpdateSession fails an update session
func (c *Manager) FailLibraryItemUpdateSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("fail")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// KeepAliveLibraryItemUpdateSession keeps an inactive update session alive.
func (c *Manager) KeepAliveLibraryItemUpdateSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("keep-alive")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// WaitOnLibraryItemUpdateSession blocks until the update session is no longer
// in the ACTIVE state.
func (c *Manager) WaitOnLibraryItemUpdateSession(
ctx context.Context, sessionID string,
interval time.Duration, intervalCallback func()) error {
// Wait until the upload operation is complete to return.
for {
session, err := c.GetLibraryItemUpdateSession(ctx, sessionID)
if err != nil {
return err
}
if session.State != "ACTIVE" {
if session.State == "ERROR" {
return session.ErrorMessage
}
return nil
}
time.Sleep(interval)
if intervalCallback != nil {
intervalCallback()
}
}
}
// CreateLibraryItemDownloadSession creates a new library item
func (c *Manager) CreateLibraryItemDownloadSession(ctx context.Context, session Session) (string, error) {
url := c.Resource(internal.LibraryItemDownloadSession)
spec := struct {
CreateSpec Session `json:"create_spec"`
}{session}
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// GetLibraryItemDownloadSession gets the download session information with status
func (c *Manager) GetLibraryItemDownloadSession(ctx context.Context, id string) (*Session, error) {
url := c.Resource(internal.LibraryItemDownloadSession).WithID(id)
var res Session
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// ListLibraryItemDownloadSession gets the list of download sessions
func (c *Manager) ListLibraryItemDownloadSession(ctx context.Context) ([]string, error) {
url := c.Resource(internal.LibraryItemDownloadSession)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
// CancelLibraryItemDownloadSession cancels an download session
func (c *Manager) CancelLibraryItemDownloadSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("cancel")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// DeleteLibraryItemDownloadSession deletes an download session
func (c *Manager) DeleteLibraryItemDownloadSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemDownloadSession).WithID(id)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// FailLibraryItemDownloadSession fails an download session
func (c *Manager) FailLibraryItemDownloadSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("fail")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}
// KeepAliveLibraryItemDownloadSession keeps an inactive download session alive.
func (c *Manager) KeepAliveLibraryItemDownloadSession(ctx context.Context, id string) error {
url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("keep-alive")
return c.Do(ctx, url.Request(http.MethodPost), nil)
}

View File

@ -0,0 +1,149 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package library
import (
"bufio"
"context"
"io"
"net/http"
"strings"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25/soap"
)
// TransferEndpoint provides information on the source of a library item file.
type TransferEndpoint struct {
URI string `json:"uri,omitempty"`
SSLCertificateThumbprint string `json:"ssl_certificate_thumbprint,omitempty"`
}
// UpdateFile is the specification for the updatesession
// operations file:add, file:get, and file:list.
type UpdateFile struct {
BytesTransferred int64 `json:"bytes_transferred,omitempty"`
Checksum *Checksum `json:"checksum_info,omitempty"`
ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"`
Name string `json:"name"`
Size int64 `json:"size,omitempty"`
SourceEndpoint *TransferEndpoint `json:"source_endpoint,omitempty"`
SourceType string `json:"source_type"`
Status string `json:"status,omitempty"`
UploadEndpoint *TransferEndpoint `json:"upload_endpoint,omitempty"`
}
// AddLibraryItemFile adds a file
func (c *Manager) AddLibraryItemFile(ctx context.Context, sessionID string, updateFile UpdateFile) (*UpdateFile, error) {
url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("add")
spec := struct {
FileSpec UpdateFile `json:"file_spec"`
}{updateFile}
var res UpdateFile
err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
if err != nil {
return nil, err
}
if res.Status == "ERROR" {
return nil, res.ErrorMessage
}
return &res, nil
}
// AddLibraryItemFileFromURI adds a file from a remote URI.
func (c *Manager) AddLibraryItemFileFromURI(
ctx context.Context,
sessionID, fileName, uri string) (*UpdateFile, error) {
n, fingerprint, err := c.getContentLengthAndFingerprint(ctx, uri)
if err != nil {
return nil, err
}
info, err := c.AddLibraryItemFile(ctx, sessionID, UpdateFile{
Name: fileName,
SourceType: "PULL",
Size: n,
SourceEndpoint: &TransferEndpoint{
URI: uri,
SSLCertificateThumbprint: fingerprint,
},
})
if err != nil {
return nil, err
}
return info, c.CompleteLibraryItemUpdateSession(ctx, sessionID)
}
// GetLibraryItemUpdateSessionFile retrieves information about a specific file
// that is a part of an update session.
func (c *Manager) GetLibraryItemUpdateSessionFile(ctx context.Context, sessionID string, fileName string) (*UpdateFile, error) {
url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("get")
spec := struct {
Name string `json:"file_name"`
}{fileName}
var res UpdateFile
return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// getContentLengthAndFingerprint gets the number of bytes returned
// by the URI as well as the SHA1 fingerprint of the peer certificate
// if the URI's scheme is https.
func (c *Manager) getContentLengthAndFingerprint(
ctx context.Context, uri string) (int64, string, error) {
resp, err := c.Head(uri)
if err != nil {
return 0, "", err
}
if resp.TLS == nil || len(resp.TLS.PeerCertificates) == 0 {
return resp.ContentLength, "", nil
}
fingerprint := c.Thumbprint(resp.Request.URL.Host)
if fingerprint == "" {
if c.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify {
fingerprint = soap.ThumbprintSHA1(resp.TLS.PeerCertificates[0])
}
}
return resp.ContentLength, fingerprint, nil
}
// ReadManifest converts an ovf manifest to a map of file name -> Checksum.
func ReadManifest(m io.Reader) (map[string]*Checksum, error) {
// expected format: openssl sha1 *.{ovf,vmdk}
c := make(map[string]*Checksum)
scanner := bufio.NewScanner(m)
for scanner.Scan() {
line := strings.SplitN(scanner.Text(), ")=", 2)
if len(line) != 2 {
continue
}
name := strings.SplitN(line[0], "(", 2)
if len(name) != 2 {
continue
}
sum := &Checksum{
Algorithm: strings.TrimSpace(name[0]),
Checksum: strings.TrimSpace(line[1]),
}
c[name[1]] = sum
}
return c, scanner.Err()
}

176
vendor/github.com/vmware/govmomi/vapi/rest/client.go generated vendored Normal file
View File

@ -0,0 +1,176 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
// Client extends soap.Client to support JSON encoding, while inheriting security features, debug tracing and session persistence.
type Client struct {
*soap.Client
}
// Session information
type Session struct {
User string `json:"user"`
Created time.Time `json:"created_time"`
LastAccessed time.Time `json:"last_accessed_time"`
}
// LocalizableMessage represents a localizable error
type LocalizableMessage struct {
Args []string `json:"args,omitempty"`
DefaultMessage string `json:"default_message,omitempty"`
ID string `json:"id,omitempty"`
}
func (m *LocalizableMessage) Error() string {
return m.DefaultMessage
}
// NewClient creates a new Client instance.
func NewClient(c *vim25.Client) *Client {
sc := c.Client.NewServiceClient(Path, "")
return &Client{sc}
}
// Resource helper for the given path.
func (c *Client) Resource(path string) *Resource {
r := &Resource{u: c.URL()}
r.u.Path = Path + path
return r
}
type Signer interface {
SignRequest(*http.Request) error
}
type signerContext struct{}
func (c *Client) WithSigner(ctx context.Context, s Signer) context.Context {
return context.WithValue(ctx, signerContext{}, s)
}
type statusError struct {
res *http.Response
}
func (e *statusError) Error() string {
return fmt.Sprintf("%s %s: %s", e.res.Request.Method, e.res.Request.URL, e.res.Status)
}
// Do sends the http.Request, decoding resBody if provided.
func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) error {
switch req.Method {
case http.MethodPost, http.MethodPatch:
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
if s, ok := ctx.Value(signerContext{}).(Signer); ok {
if err := s.SignRequest(req); err != nil {
return err
}
}
return c.Client.Do(ctx, req, func(res *http.Response) error {
switch res.StatusCode {
case http.StatusOK:
case http.StatusBadRequest:
// TODO: structured error types
detail, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
return fmt.Errorf("%s: %s", res.Status, bytes.TrimSpace(detail))
default:
return &statusError{res}
}
if resBody == nil {
return nil
}
switch b := resBody.(type) {
case io.Writer:
_, err := io.Copy(b, res.Body)
return err
default:
val := struct {
Value interface{} `json:"value,omitempty"`
}{
resBody,
}
return json.NewDecoder(res.Body).Decode(&val)
}
})
}
// Login creates a new session via Basic Authentication with the given url.Userinfo.
func (c *Client) Login(ctx context.Context, user *url.Userinfo) error {
req := c.Resource(internal.SessionPath).Request(http.MethodPost)
if user != nil {
if password, ok := user.Password(); ok {
req.SetBasicAuth(user.Username(), password)
}
}
return c.Do(ctx, req, nil)
}
func (c *Client) LoginByToken(ctx context.Context) error {
return c.Login(ctx, nil)
}
// Session returns the user's current session.
// Nil is returned if the session is not authenticated.
func (c *Client) Session(ctx context.Context) (*Session, error) {
var s Session
req := c.Resource(internal.SessionPath).WithAction("get").Request(http.MethodPost)
err := c.Do(ctx, req, &s)
if err != nil {
if e, ok := err.(*statusError); ok {
if e.res.StatusCode == http.StatusUnauthorized {
return nil, nil
}
}
return nil, err
}
return &s, nil
}
// Logout deletes the current session.
func (c *Client) Logout(ctx context.Context) error {
req := c.Resource(internal.SessionPath).Request(http.MethodDelete)
return c.Do(ctx, req, nil)
}

89
vendor/github.com/vmware/govmomi/vapi/rest/resource.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/url"
)
const (
Path = "/rest"
)
// Resource wraps url.URL with helpers
type Resource struct {
u *url.URL
}
func (r *Resource) String() string {
return r.u.String()
}
// WithID appends id to the URL.Path
func (r *Resource) WithID(id string) *Resource {
r.u.Path += "/id:" + id
return r
}
// WithAction sets adds action to the URL.RawQuery
func (r *Resource) WithAction(action string) *Resource {
return r.WithParam("~action", action)
}
// WithParam sets adds a parameter to the URL.RawQuery
func (r *Resource) WithParam(name string, value string) *Resource {
r.u.RawQuery = url.Values{
name: []string{value},
}.Encode()
return r
}
// Request returns a new http.Request for the given method.
// An optional body can be provided for POST and PATCH methods.
func (r *Resource) Request(method string, body ...interface{}) *http.Request {
rdr := io.MultiReader() // empty body by default
if len(body) != 0 {
rdr = encode(body[0])
}
req, err := http.NewRequest(method, r.u.String(), rdr)
if err != nil {
panic(err)
}
return req
}
type errorReader struct {
e error
}
func (e errorReader) Read([]byte) (int, error) {
return -1, e.e
}
// encode body as JSON, deferring any errors until io.Reader is used.
func encode(body interface{}) io.Reader {
var b bytes.Buffer
err := json.NewEncoder(&b).Encode(body)
if err != nil {
return errorReader{err}
}
return &b
}

View File

@ -0,0 +1,261 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vcenter
import (
"context"
"fmt"
"net/http"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25/types"
)
// AdditionalParams are additional OVF parameters which can be specified for a deployment target.
// This structure is a union where based on Type, only one of each commented section will be set.
type AdditionalParams struct {
Class string `json:"@class"`
Type string `json:"type"`
// DeploymentOptionParams
SelectedKey string `json:"selected_key,omitempty"`
DeploymentOptions []DeploymentOption `json:"deployment_options,omitempty"`
// ExtraConfigs
ExtraConfig []ExtraConfig `json:"extra_configs,omitempty"`
// PropertyParams
Properties []Property `json:"properties,omitempty"`
// SizeParams
ApproximateSparseDeploymentSize int64 `json:"approximate_sparse_deployment_size,omitempty"`
VariableDiskSize bool `json:"variable_disk_size,omitempty"`
ApproximateDownloadSize int64 `json:"approximate_download_size,omitempty"`
ApproximateFlatDeploymentSize int64 `json:"approximate_flat_deployment_size,omitempty"`
// IpAllocationParams
SupportedAllocationScheme []string `json:"supported_allocation_scheme,omitempty"`
SupportedIPProtocol []string `json:"supported_ip_protocol,omitempty"`
SupportedIPAllocationPolicy []string `json:"supported_ip_allocation_policy,omitempty"`
IPAllocationPolicy string `json:"ip_allocation_policy,omitempty"`
IPProtocol string `json:"ip_protocol,omitempty"`
// UnknownSections
UnknownSections []UnknownSection `json:"unknown_sections,omitempty"`
}
const (
ClassOvfParams = "com.vmware.vcenter.ovf.ovf_params"
ClassPropertyParams = "com.vmware.vcenter.ovf.property_params"
TypeDeploymentOptionParams = "DeploymentOptionParams"
TypeExtraConfigParams = "ExtraConfigParams"
TypeExtraConfigs = "ExtraConfigs"
TypeIPAllocationParams = "IpAllocationParams"
TypePropertyParams = "PropertyParams"
TypeSizeParams = "SizeParams"
)
// DeploymentOption contains the information about a deployment option as defined in the OVF specification
type DeploymentOption struct {
Key string `json:"key,omitempty"`
Label string `json:"label,omitempty"`
Description string `json:"description,omitempty"`
DefaultChoice bool `json:"default_choice,omitempty"`
}
// ExtraConfig contains information about a vmw:ExtraConfig OVF element
type ExtraConfig struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
VirtualSystemID string `json:"virtual_system_id,omitempty"`
}
// Property contains information about a property in an OVF package
type Property struct {
Category string `json:"category,omitempty"`
ClassID string `json:"class_id,omitempty"`
Description string `json:"description,omitempty"`
ID string `json:"id,omitempty"`
InstanceID string `json:"instance_id,omitempty"`
Label string `json:"label,omitempty"`
Type string `json:"type,omitempty"`
UIOptional bool `json:"ui_optional,omitempty"`
Value string `json:"value,omitempty"`
}
// UnknownSection contains information about an unknown section in an OVF package
type UnknownSection struct {
Tag string `json:"tag,omitempty"`
Info string `json:"info,omitempty"`
}
// NetworkMapping specifies the target network to use for sections of type ovf:NetworkSection in the OVF descriptor
type NetworkMapping struct {
Key string `json:"key"`
Value string `json:"value"`
}
// StorageGroupMapping defines the storage deployment target and storage provisioning type for a section of type vmw:StorageGroupSection in the OVF descriptor
type StorageGroupMapping struct {
Type string `json:"type"`
StorageProfileID string `json:"storage_profile_id,omitempty"`
DatastoreID string `json:"datastore_id,omitempty"`
Provisioning string `json:"provisioning,omitempty"`
}
// StorageMapping specifies the target storage to use for sections of type vmw:StorageGroupSection in the OVF descriptor
type StorageMapping struct {
Key string `json:"key"`
Value StorageGroupMapping `json:"value"`
}
// DeploymentSpec is the deployment specification for the deployment
type DeploymentSpec struct {
Name string `json:"name,omitempty"`
Annotation string `json:"annotation,omitempty"`
AcceptAllEULA bool `json:"accept_all_EULA,omitempty"`
NetworkMappings []NetworkMapping `json:"network_mappings,omitempty"`
StorageMappings []StorageMapping `json:"storage_mappings,omitempty"`
StorageProvisioning string `json:"storage_provisioning,omitempty"`
StorageProfileID string `json:"storage_profile_id,omitempty"`
Locale string `json:"locale,omitempty"`
Flags []string `json:"flags,omitempty"`
AdditionalParams []AdditionalParams `json:"additional_parameters,omitempty"`
DefaultDatastoreID string `json:"default_datastore_id,omitempty"`
}
// Target is the target for the deployment
type Target struct {
ResourcePoolID string `json:"resource_pool_id,omitempty"`
HostID string `json:"host_id,omitempty"`
FolderID string `json:"folder_id,omitempty"`
}
// Deploy contains the information to start the deployment of a library OVF
type Deploy struct {
DeploymentSpec `json:"deployment_spec,omitempty"`
Target `json:"target,omitempty"`
}
// Error is a SERVER error
type Error struct {
Class string `json:"@class,omitempty"`
Messages []rest.LocalizableMessage `json:"messages,omitempty"`
}
// ParseIssue is a parse issue struct
type ParseIssue struct {
Category string `json:"@classcategory,omitempty"`
File string `json:"file,omitempty"`
LineNumber int64 `json:"line_number,omitempty"`
ColumnNumber int64 `json:"column_number,omitempty"`
Message rest.LocalizableMessage `json:"message,omitempty"`
}
// OVFError is a list of errors from create or deploy
type OVFError struct {
Category string `json:"category,omitempty"`
Error *Error `json:"error,omitempty"`
Issues []ParseIssue `json:"issues,omitempty"`
Message *rest.LocalizableMessage `json:"message,omitempty"`
}
// ResourceID is a managed object reference for a deployed resource.
type ResourceID struct {
Type string `json:"type,omitempty"`
Value string `json:"id,omitempty"`
}
// DeploymentError is an error that occurs when deploying and OVF from
// a library item.
type DeploymentError struct {
Errors []OVFError `json:"errors,omitempty"`
}
// Error implements the error interface
func (e *DeploymentError) Error() string {
msg := ""
if len(e.Errors) != 0 {
err := e.Errors[0]
if err.Message != nil {
msg = err.Message.DefaultMessage
} else if err.Error != nil && len(err.Error.Messages) != 0 {
msg = err.Error.Messages[0].DefaultMessage
}
}
if msg == "" {
msg = fmt.Sprintf("%#v", e)
}
return "deploy error: " + msg
}
// Deployment is the results from issuing a library OVF deployment
type Deployment struct {
Succeeded bool `json:"succeeded,omitempty"`
ResourceID *ResourceID `json:"resource_id,omitempty"`
Error *DeploymentError `json:"error,omitempty"`
}
// FilterRequest contains the information to start a vcenter filter call
type FilterRequest struct {
Target `json:"target,omitempty"`
}
// FilterResponse returns information from the vcenter filter call
type FilterResponse struct {
EULAs []string `json:"EULAs,omitempty"`
AdditionalParams []AdditionalParams `json:"additional_params,omitempty"`
Annotation string `json:"Annotation,omitempty"`
Name string `json:"name,omitempty"`
Networks []string `json:"Networks,omitempty"`
StorageGroups []string `json:"storage_groups,omitempty"`
}
// Manager extends rest.Client, adding content library related methods.
type Manager struct {
*rest.Client
}
// NewManager creates a new Manager instance with the given client.
func NewManager(client *rest.Client) *Manager {
return &Manager{
Client: client,
}
}
// DeployLibraryItem deploys a library OVF
func (c *Manager) DeployLibraryItem(ctx context.Context, libraryItemID string, deploy Deploy) (*types.ManagedObjectReference, error) {
url := c.Resource(internal.VCenterOVFLibraryItem).WithID(libraryItemID).WithAction("deploy")
var res Deployment
err := c.Do(ctx, url.Request(http.MethodPost, deploy), &res)
if err != nil {
return nil, err
}
if res.Succeeded {
ref := types.ManagedObjectReference(*res.ResourceID)
return &ref, nil
}
return nil, res.Error
}
// FilterLibraryItem deploys a library OVF
func (c *Manager) FilterLibraryItem(ctx context.Context, libraryItemID string, filter FilterRequest) (FilterResponse, error) {
url := c.Resource(internal.VCenterOVFLibraryItem).WithID(libraryItemID).WithAction("filter")
var res FilterResponse
return res, c.Do(ctx, url.Request(http.MethodPost, filter), &res)
}

View File

@ -0,0 +1,290 @@
/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vcenter
import (
"context"
"crypto/sha1"
"fmt"
"log"
"net/http"
"path"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/library"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
// vcenter vm template
// The vcenter.vm_template API provides structures and services that will let its client manage VMTX template in Content Library.
// http://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/index.html#SVC_com.vmware.vcenter.vm_template.library_items
// Template create spec
type Template struct {
Description string `json:"description,omitempty"`
DiskStorage *DiskStorage `json:"disk_storage,omitempty"`
DiskStorageOverrides []DiskStorageOverride `json:"disk_storage_overrides,omitempty"`
Library string `json:"library,omitempty"`
Name string `json:"name,omitempty"`
Placement *Placement `json:"placement,omitempty"`
SourceVM string `json:"source_vm,omitempty"`
VMHomeStorage *DiskStorage `json:"vm_home_storage,omitempty"`
}
// TemplateInfo for a VM template contained in an existing library item
type TemplateInfo struct {
GuestOS string `json:"guest_OS,omitempty"`
// TODO...
}
// Placement information used to place the virtual machine template
type Placement struct {
ResourcePool string `json:"resource_pool,omitempty"`
Host string `json:"host,omitempty"`
Folder string `json:"folder,omitempty"`
Cluster string `json:"cluster,omitempty"`
}
// StoragePolicy for DiskStorage
type StoragePolicy struct {
Policy string `json:"policy,omitempty"`
Type string `json:"type"`
}
// DiskStorage defines the storage specification for VM files
type DiskStorage struct {
Datastore string `json:"datastore,omitempty"`
StoragePolicy *StoragePolicy `json:"storage_policy,omitempty"`
}
// DiskStorageOverride storage specification for individual disks in the virtual machine template
type DiskStorageOverride struct {
Key string `json:"key"`
Value DiskStorage `json:"value"`
}
// GuestCustomization spec to apply to the deployed VM
type GuestCustomization struct {
Name string `json:"name,omitempty"`
}
// HardwareCustomization spec which specifies updates to the deployed VM
type HardwareCustomization struct {
// TODO
}
// DeployTemplate specification of how a library VM template clone should be deployed.
type DeployTemplate struct {
Description string `json:"description,omitempty"`
DiskStorage *DiskStorage `json:"disk_storage,omitempty"`
DiskStorageOverrides []DiskStorageOverride `json:"disk_storage_overrides,omitempty"`
GuestCustomization *GuestCustomization `json:"guest_customization,omitempty"`
HardwareCustomization *HardwareCustomization `json:"hardware_customization,omitempty"`
Name string `json:"name,omitempty"`
Placement *Placement `json:"placement,omitempty"`
PoweredOn bool `json:"powered_on"`
VMHomeStorage *DiskStorage `json:"vm_home_storage,omitempty"`
}
// CheckOut specification
type CheckOut struct {
Name string `json:"name,omitempty"`
Placement *Placement `json:"placement,omitempty"`
PoweredOn bool `json:"powered_on,omitempty"`
}
// CheckIn specification
type CheckIn struct {
Message string `json:"message"`
}
// CreateTemplate creates a library item in content library from an existing VM
func (c *Manager) CreateTemplate(ctx context.Context, vmtx Template) (string, error) {
url := c.Resource(internal.VCenterVMTXLibraryItem)
var res string
spec := struct {
Template `json:"spec"`
}{vmtx}
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// DeployTemplateLibraryItem deploys a VM as a copy of the source VM template contained in the given library item
func (c *Manager) DeployTemplateLibraryItem(ctx context.Context, libraryItemID string, deploy DeployTemplate) (*types.ManagedObjectReference, error) {
url := c.Resource(path.Join(internal.VCenterVMTXLibraryItem, libraryItemID)).WithParam("action", "deploy")
var res string
spec := struct {
DeployTemplate `json:"spec"`
}{deploy}
err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
if err != nil {
return nil, err
}
return &types.ManagedObjectReference{Type: "VirtualMachine", Value: res}, nil
}
// CheckOut a library item containing a VM template.
func (c *Manager) CheckOut(ctx context.Context, libraryItemID string, checkout *CheckOut) (*types.ManagedObjectReference, error) {
url := c.Resource(path.Join(internal.VCenterVMTXLibraryItem, libraryItemID, "check-outs")).WithParam("action", "check-out")
var res string
spec := struct {
*CheckOut `json:"spec"`
}{checkout}
err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
if err != nil {
return nil, err
}
return &types.ManagedObjectReference{Type: "VirtualMachine", Value: res}, nil
}
// CheckIn a VM into the library item.
func (c *Manager) CheckIn(ctx context.Context, libraryItemID string, vm mo.Reference, checkin *CheckIn) (string, error) {
p := path.Join(internal.VCenterVMTXLibraryItem, libraryItemID, "check-outs", vm.Reference().Value)
url := c.Resource(p).WithParam("action", "check-in")
var res string
spec := struct {
*CheckIn `json:"spec"`
}{checkin}
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// TemplateLibrary params for synchronizing subscription library OVF items to VM Template items
type TemplateLibrary struct {
Source library.Library
Destination library.Library
Placement Target
Include func(library.Item, *library.Item) bool
SyncItem func(context.Context, library.Item, *Deploy, *Template) error
}
func (c *Manager) includeTemplateLibraryItem(src library.Item, dst *library.Item) bool {
return dst == nil
}
// SyncTemplateLibraryItem deploys an Library OVF item from which a VM template (vmtx) Library item is created.
// The deployed VM is deleted after being converted to a Library vmtx item.
func (c *Manager) SyncTemplateLibraryItem(ctx context.Context, item library.Item, deploy *Deploy, spec *Template) error {
destroy := false
if spec.SourceVM == "" {
ref, err := c.DeployLibraryItem(ctx, item.ID, *deploy)
if err != nil {
return err
}
destroy = true
spec.SourceVM = ref.Value
}
_, err := c.CreateTemplate(ctx, *spec)
if destroy {
// Delete source VM regardless of CreateTemplate result
url := c.Resource("/vcenter/vm/" + spec.SourceVM)
derr := c.Do(ctx, url.Request(http.MethodDelete), nil)
if derr != nil {
if err == nil {
// Return Delete error if CreateTemplate was successful
return derr
}
// Return CreateTemplate error and just log Delete error
log.Printf("destroy %s: %s", spec.SourceVM, derr)
}
}
return err
}
func vmtxSourceName(l library.Library, item library.Item) string {
sum := sha1.Sum([]byte(path.Join(l.Name, item.Name)))
return fmt.Sprintf("vmtx-src-%x", sum)
}
// SyncTemplateLibrary converts TemplateLibrary.Source OVF items to VM Template items within TemplateLibrary.Destination
// The optional TemplateLibrary.Include func can be used to filter which items are synced.
// By default all items that don't exist in the Destination library are synced.
// The optional TemplateLibrary.SyncItem func can be used to change how the item is synced, by default SyncTemplateLibraryItem is used.
func (c *Manager) SyncTemplateLibrary(ctx context.Context, l TemplateLibrary, items ...library.Item) error {
m := library.NewManager(c.Client)
var err error
if len(items) == 0 {
items, err = m.GetLibraryItems(ctx, l.Source.ID)
if err != nil {
return err
}
}
templates, err := m.GetLibraryItems(ctx, l.Destination.ID)
if err != nil {
return err
}
existing := make(map[string]*library.Item)
for i := range templates {
existing[templates[i].Name] = &templates[i]
}
include := l.Include
if include == nil {
include = c.includeTemplateLibraryItem
}
sync := l.SyncItem
if sync == nil {
sync = c.SyncTemplateLibraryItem
}
for _, item := range items {
if item.Type != library.ItemTypeOVF {
continue
}
// Deploy source VM from library ovf item
deploy := Deploy{
DeploymentSpec: DeploymentSpec{
Name: vmtxSourceName(l.Destination, item),
DefaultDatastoreID: l.Destination.Storage[0].DatastoreID,
AcceptAllEULA: true,
},
Target: l.Placement,
}
// Create library vmtx item from source VM
storage := &DiskStorage{
Datastore: deploy.DeploymentSpec.DefaultDatastoreID,
}
spec := Template{
Name: item.Name,
Library: l.Destination.ID,
DiskStorage: storage,
VMHomeStorage: storage,
Placement: &Placement{
Folder: deploy.Target.FolderID,
ResourcePool: deploy.Target.ResourcePoolID,
},
}
if !l.Include(item, existing[item.Name]) {
continue
}
if err = sync(ctx, item, &deploy, &spec); err != nil {
return err
}
}
return nil
}

4
vendor/modules.txt vendored
View File

@ -580,6 +580,10 @@ github.com/vmware/govmomi/ovf
github.com/vmware/govmomi/property
github.com/vmware/govmomi/session
github.com/vmware/govmomi/task
github.com/vmware/govmomi/vapi/internal
github.com/vmware/govmomi/vapi/library
github.com/vmware/govmomi/vapi/rest
github.com/vmware/govmomi/vapi/vcenter
github.com/vmware/govmomi/vim25
github.com/vmware/govmomi/vim25/debug
github.com/vmware/govmomi/vim25/methods

View File

@ -171,6 +171,35 @@ can be done via environment variable:
@include 'builder/vsphere/common/OutputConfig-not-required.mdx'
### Content Library Import Configuration
@include 'builder/vsphere/common/ContentLibraryDestinationConfig.mdx'
@include 'builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx'
Minimal example of usage:
<Tabs>
<Tab heading="JSON">
```json
"content_library_destination" : {
"library": "Packer Library Test"
}
```
</Tab>
<Tab heading="HCL2">
```hcl
content_library_destination {
library = "Packer Library Test"
}
```
</Tab>
</Tabs>
## Working with Clusters
#### Standalone Hosts

View File

@ -174,6 +174,35 @@ from the datastore. Example:
@include 'builder/vsphere/common/OutputConfig-not-required.mdx'
### Content Library Import Configuration
@include 'builder/vsphere/common/ContentLibraryDestinationConfig.mdx'
@include 'builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx'
Minimal example of usage:
<Tabs>
<Tab heading="JSON">
```json
"content_library_destination" : {
"library": "Packer Library Test"
}
```
</Tab>
<Tab heading="HCL2">
```hcl
content_library_destination {
library = "Packer Library Test"
}
```
</Tab>
</Tabs>
### Extra Configuration Parameters
@include 'builder/vsphere/common/ConfigParamsConfig-not-required.mdx'

View File

@ -5,4 +5,10 @@
- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`.
- `export` (\*common.ExportConfig) - Export
- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file.
The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
- `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.

View File

@ -0,0 +1,30 @@
<!-- Code generated from the comments of the ContentLibraryDestinationConfig struct in builder/vsphere/common/step_import_to_content_library.go; DO NOT EDIT MANUALLY -->
- `library` (string) - Name of the library in which the new library item containing the VM template should be created.
The Content Library should be of type Local to allow deploying virtual machines.
- `name` (string) - Name of the library item that will be created. The name of the item should be different from [vm_name](#vm_name).
Defaults to [vm_name](#vm_name) + timestamp.
- `description` (string) - Description of the library item that will be created. Defaults to "Packer imported [vm_name](#vm_name) VM template".
- `cluster` (string) - Cluster onto which the virtual machine template should be placed.
If cluster and resource_pool are both specified, resource_pool must belong to cluster.
If cluster and host are both specified, host must be a member of cluster.
Defaults to [cluster](#cluster).
- `folder` (string) - Virtual machine folder into which the virtual machine template should be placed.
Defaults to the same folder as the source virtual machine.
- `host` (string) - Host onto which the virtual machine template should be placed.
If host and resource_pool are both specified, resource_pool must belong to host.
If host and cluster are both specified, host must be a member of cluster.
Defaults to [host](#host).
- `resource_pool` (string) - Resource pool into which the virtual machine template should be placed.
Defaults to [resource_pool](#resource_pool). if [resource_pool](#resource_pool) is also unset,
the system will attempt to choose a suitable resource pool for the virtual machine template.
- `datastore` (string) - The datastore for the virtual machine template's configuration and log files.
Defaults to the storage backing associated with the library specified by library.

View File

@ -0,0 +1,3 @@
<!-- Code generated from the comments of the ContentLibraryDestinationConfig struct in builder/vsphere/common/step_import_to_content_library.go; DO NOT EDIT MANUALLY -->
With this configuration Packer creates a library item in a content library whose content is a virtual machine template created from the just built VM.
The virtual machine template is stored in a newly created library item.

View File

@ -7,4 +7,8 @@
- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file.
The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
- `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.