From 9569d35d14097cbaec33bc0f38782483a90d6baa Mon Sep 17 00:00:00 2001 From: Aishwarya Thangappa Date: Wed, 1 Jan 2020 23:23:04 -0800 Subject: [PATCH] Set expiry for image versions in SIG Updates azure builder to support setting end-of-life-date for image versions in shared image gallery. In addition, this change adds the ability to set the global replica count for the image version and allows the vms deployed from the latest version of the Image Definition to exclude this Image Version. --- builder/azure/arm/builder.go | 3 + builder/azure/arm/config.go | 10 + builder/azure/arm/config.hcl2spec.go | 248 +++++++++--------- .../step_publish_to_shared_image_gallery.go | 47 +++- ...ep_publish_to_shared_image_gallery_test.go | 4 +- builder/azure/common/constants/stateBag.go | 38 ++- go.mod | 2 +- .../azure/arm/_Config-not-required.html.md | 10 + 8 files changed, 214 insertions(+), 148 deletions(-) diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index 981e22e92..f1cf0fed3 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -395,6 +395,9 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) { stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, b.config.SharedGalleryDestination.SigDestinationImageName) stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion) stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) + stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate, b.config.SharedGalleryImageVersionEndOfLifeDate) + stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount, b.config.SharedGalleryImageVersionReplicaCount) + stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest, b.config.SharedGalleryImageVersionExcludeFromLatest) } } diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 0f4b49a51..976dc2c84 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -137,6 +137,16 @@ type Config struct { // its default of "60m" (valid time units include `s` for seconds, `m` for // minutes, and `h` for hours.) SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"` + // The end of life date (2006-01-02T15:04:05.99Z) of the gallery Image Version. This property + // can be used for decommissioning purposes. + SharedGalleryImageVersionEndOfLifeDate string `mapstructure:"shared_gallery_image_version_end_of_life_date" required:"false"` + // The number of replicas of the Image Version to be created per region. This + // property would take effect for a region when regionalReplicaCount is not specified. + // Replica count must be between 1 and 10. + SharedGalleryImageVersionReplicaCount int32 `mapstructure:"shared_image_gallery_replica_count" required:"false"` + // If set to true, Virtual Machines deployed from the latest version of the + // Image Definition won't use this Image Version. + SharedGalleryImageVersionExcludeFromLatest bool `mapstructure:"shared_gallery_image_version_exclude_from_latest" required:"false"` // PublisherName for your base image. See // [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/) // for details. diff --git a/builder/azure/arm/config.hcl2spec.go b/builder/azure/arm/config.hcl2spec.go index 317528478..826100044 100644 --- a/builder/azure/arm/config.hcl2spec.go +++ b/builder/azure/arm/config.hcl2spec.go @@ -9,102 +9,105 @@ 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"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` - CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"` - ClientID *string `mapstructure:"client_id" cty:"client_id"` - ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"` - ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"` - ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"` - ObjectID *string `mapstructure:"object_id" cty:"object_id"` - TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"` - SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"` - CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix"` - CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name"` - SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" required:"false" cty:"shared_image_gallery"` - SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination"` - SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout"` - ImagePublisher *string `mapstructure:"image_publisher" required:"true" cty:"image_publisher"` - ImageOffer *string `mapstructure:"image_offer" required:"true" cty:"image_offer"` - ImageSku *string `mapstructure:"image_sku" required:"true" cty:"image_sku"` - ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"` - ImageUrl *string `mapstructure:"image_url" required:"false" cty:"image_url"` - CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" required:"false" cty:"custom_managed_image_resource_group_name"` - CustomManagedImageName *string `mapstructure:"custom_managed_image_name" required:"false" cty:"custom_managed_image_name"` - Location *string `mapstructure:"location" cty:"location"` - VMSize *string `mapstructure:"vm_size" required:"false" cty:"vm_size"` - ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name"` - ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name"` - ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type"` - ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name"` - ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix"` - ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient"` - AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags"` - ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name"` - StorageAccount *string `mapstructure:"storage_account" cty:"storage_account"` - TempComputeName *string `mapstructure:"temp_compute_name" required:"false" cty:"temp_compute_name"` - TempResourceGroupName *string `mapstructure:"temp_resource_group_name" cty:"temp_resource_group_name"` - BuildResourceGroupName *string `mapstructure:"build_resource_group_name" cty:"build_resource_group_name"` - PrivateVirtualNetworkWithPublicIp *bool `mapstructure:"private_virtual_network_with_public_ip" required:"false" cty:"private_virtual_network_with_public_ip"` - VirtualNetworkName *string `mapstructure:"virtual_network_name" required:"false" cty:"virtual_network_name"` - VirtualNetworkSubnetName *string `mapstructure:"virtual_network_subnet_name" required:"false" cty:"virtual_network_subnet_name"` - VirtualNetworkResourceGroupName *string `mapstructure:"virtual_network_resource_group_name" required:"false" cty:"virtual_network_resource_group_name"` - CustomDataFile *string `mapstructure:"custom_data_file" required:"false" cty:"custom_data_file"` - PlanInfo *FlatPlanInformation `mapstructure:"plan_info" required:"false" cty:"plan_info"` - PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout"` - OSType *string `mapstructure:"os_type" required:"false" cty:"os_type"` - OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb"` - AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size"` - DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type"` - AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses" cty:"allowed_inbound_ip_addresses"` - UserName *string `cty:"user_name"` - Password *string `cty:"password"` - Type *string `mapstructure:"communicator" cty:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` - AsyncResourceGroupDelete *bool `mapstructure:"async_resourcegroup_delete" required:"false" cty:"async_resourcegroup_delete"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` + CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"` + ClientID *string `mapstructure:"client_id" cty:"client_id"` + ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"` + ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"` + ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"` + ObjectID *string `mapstructure:"object_id" cty:"object_id"` + TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"` + SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"` + CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix"` + CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name"` + SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" required:"false" cty:"shared_image_gallery"` + SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination"` + SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout"` + SharedGalleryImageVersionEndOfLifeDate *string `mapstructure:"shared_gallery_image_version_end_of_life_date" required:"false" cty:"shared_gallery_image_version_end_of_life_date"` + SharedGalleryImageVersionReplicaCount *int32 `mapstructure:"shared_image_gallery_replica_count" required:"false" cty:"shared_image_gallery_replica_count"` + SharedGalleryImageVersionExcludeFromLatest *bool `mapstructure:"shared_gallery_image_version_exclude_from_latest" required:"false" cty:"shared_gallery_image_version_exclude_from_latest"` + ImagePublisher *string `mapstructure:"image_publisher" required:"true" cty:"image_publisher"` + ImageOffer *string `mapstructure:"image_offer" required:"true" cty:"image_offer"` + ImageSku *string `mapstructure:"image_sku" required:"true" cty:"image_sku"` + ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"` + ImageUrl *string `mapstructure:"image_url" required:"false" cty:"image_url"` + CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" required:"false" cty:"custom_managed_image_resource_group_name"` + CustomManagedImageName *string `mapstructure:"custom_managed_image_name" required:"false" cty:"custom_managed_image_name"` + Location *string `mapstructure:"location" cty:"location"` + VMSize *string `mapstructure:"vm_size" required:"false" cty:"vm_size"` + ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name"` + ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name"` + ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type"` + ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name"` + ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix"` + ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient"` + AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags"` + ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name"` + StorageAccount *string `mapstructure:"storage_account" cty:"storage_account"` + TempComputeName *string `mapstructure:"temp_compute_name" required:"false" cty:"temp_compute_name"` + TempResourceGroupName *string `mapstructure:"temp_resource_group_name" cty:"temp_resource_group_name"` + BuildResourceGroupName *string `mapstructure:"build_resource_group_name" cty:"build_resource_group_name"` + PrivateVirtualNetworkWithPublicIp *bool `mapstructure:"private_virtual_network_with_public_ip" required:"false" cty:"private_virtual_network_with_public_ip"` + VirtualNetworkName *string `mapstructure:"virtual_network_name" required:"false" cty:"virtual_network_name"` + VirtualNetworkSubnetName *string `mapstructure:"virtual_network_subnet_name" required:"false" cty:"virtual_network_subnet_name"` + VirtualNetworkResourceGroupName *string `mapstructure:"virtual_network_resource_group_name" required:"false" cty:"virtual_network_resource_group_name"` + CustomDataFile *string `mapstructure:"custom_data_file" required:"false" cty:"custom_data_file"` + PlanInfo *FlatPlanInformation `mapstructure:"plan_info" required:"false" cty:"plan_info"` + PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout"` + OSType *string `mapstructure:"os_type" required:"false" cty:"os_type"` + OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb"` + AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size"` + DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type"` + AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses" cty:"allowed_inbound_ip_addresses"` + UserName *string `cty:"user_name"` + Password *string `cty:"password"` + Type *string `mapstructure:"communicator" cty:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` + AsyncResourceGroupDelete *bool `mapstructure:"async_resourcegroup_delete" required:"false" cty:"async_resourcegroup_delete"` } // FlatMapstructure returns a new FlatConfig. @@ -119,31 +122,34 @@ func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } // The decoded values from this spec will then be applied to a FlatConfig. func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: cty.String, Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, - "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, - "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, - "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, - "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, - "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, - "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, - "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, - "capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false}, - "capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false}, - "shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())}, - "shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, - "shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false}, - "image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false}, - "image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false}, - "image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false}, + "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, + "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, + "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, + "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, + "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, + "packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: cty.String, Required: false}, + "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, + "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, + "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, + "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, + "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, + "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, + "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, + "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, + "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, + "capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false}, + "capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false}, + "shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())}, + "shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, + "shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false}, + "shared_gallery_image_version_end_of_life_date": &hcldec.AttrSpec{Name: "shared_gallery_image_version_end_of_life_date", Type: cty.String, Required: false}, + "shared_image_gallery_replica_count": &hcldec.AttrSpec{Name: "shared_image_gallery_replica_count", Type: cty.Number, Required: false}, + "shared_gallery_image_version_exclude_from_latest": &hcldec.AttrSpec{Name: "shared_gallery_image_version_exclude_from_latest", Type: cty.Bool, Required: false}, + "image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false}, + "image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false}, + "image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false}, + "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, + "image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false}, "custom_managed_image_resource_group_name": &hcldec.AttrSpec{Name: "custom_managed_image_resource_group_name", Type: cty.String, Required: false}, "custom_managed_image_name": &hcldec.AttrSpec{Name: "custom_managed_image_name", Type: cty.String, Required: false}, "location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false}, diff --git a/builder/azure/arm/step_publish_to_shared_image_gallery.go b/builder/azure/arm/step_publish_to_shared_image_gallery.go index f30b6fa96..df1933c72 100644 --- a/builder/azure/arm/step_publish_to_shared_image_gallery.go +++ b/builder/azure/arm/step_publish_to_shared_image_gallery.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" + "github.com/Azure/go-autorest/autorest/date" "github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" @@ -12,7 +13,7 @@ import ( type StepPublishToSharedImageGallery struct { client *AzureClient - publish func(ctx context.Context, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) + publish func(ctx context.Context, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion string, miSigReplicationRegions []string, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error) say func(message string) error func(e error) toSIG func() bool @@ -36,7 +37,7 @@ func NewStepPublishToSharedImageGallery(client *AzureClient, ui packer.Ui, confi return step } -func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, miSigPubRg string, miSIGalleryName string, miSGImageName string, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) { +func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, miSigPubRg string, miSIGalleryName string, miSGImageName string, miSGImageVersion string, miSigReplicationRegions []string, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error) { replicationRegions := make([]compute.TargetRegion, len(miSigReplicationRegions)) for i, v := range miSigReplicationRegions { @@ -44,6 +45,16 @@ func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiI replicationRegions[i] = compute.TargetRegion{Name: ®ionName} } + var endOfLifeDate *date.Time + if miSGImageVersionEndOfLifeDate != "" { + parseDate, err := date.ParseTime("2006-01-02T15:04:05.99Z", miSGImageVersionEndOfLifeDate) + if err != nil { + panic(err) + } + endOfLifeDate = &date.Time{Time: parseDate} + } else { + endOfLifeDate = (*date.Time)(nil) + } galleryImageVersion := compute.GalleryImageVersion{ Location: &location, Tags: tags, @@ -54,7 +65,10 @@ func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiI ID: &mdiID, }, }, - TargetRegions: &replicationRegions, + TargetRegions: &replicationRegions, + EndOfLifeDate: endOfLifeDate, + ExcludeFromLatest: &miSGImageVersionExcludeFromLatest, + ReplicaCount: &miSigReplicaCount, }, }, } @@ -102,14 +116,27 @@ func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag mult var targetManagedImageName = stateBag.Get(constants.ArmManagedImageName).(string) var managedImageSubscription = stateBag.Get(constants.ArmManagedImageSubscription).(string) var mdiID = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageSubscription, targetManagedImageResourceGroupName, targetManagedImageName) + miSGImageVersionEndOfLifeDate, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate).(string) + miSGImageVersionExcludeFromLatest, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest).(bool) + miSigReplicaCount, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount).(int32) + // Replica count must be between 1 and 10 inclusive. + if miSigReplicaCount <= 0 { + miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMinReplicaCount + } else if miSigReplicaCount > 10 { + miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMaxReplicaCount + } - s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID)) - s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", miSigPubRg)) - s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", miSIGalleryName)) - s.say(fmt.Sprintf(" -> SIG image name : '%s'", miSGImageName)) - s.say(fmt.Sprintf(" -> SIG image version : '%s'", miSGImageVersion)) - s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", miSigReplicationRegions)) - createdGalleryImageVersionID, err := s.publish(ctx, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, location, tags) + s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID)) + s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", miSigPubRg)) + s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", miSIGalleryName)) + s.say(fmt.Sprintf(" -> SIG image name : '%s'", miSGImageName)) + s.say(fmt.Sprintf(" -> SIG image version : '%s'", miSGImageVersion)) + s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", miSigReplicationRegions)) + s.say(fmt.Sprintf(" -> SIG image version endoflife date : '%s'", miSGImageVersionEndOfLifeDate)) + s.say(fmt.Sprintf(" -> SIG image version exclude from latest : '%t'", miSGImageVersionExcludeFromLatest)) + s.say(fmt.Sprintf(" -> SIG replica count [1, 10] : '%d'", miSigReplicaCount)) + + createdGalleryImageVersionID, err := s.publish(ctx, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, miSGImageVersionEndOfLifeDate, miSGImageVersionExcludeFromLatest, miSigReplicaCount, location, tags) if err != nil { stateBag.Put(constants.Error, err) diff --git a/builder/azure/arm/step_publish_to_shared_image_gallery_test.go b/builder/azure/arm/step_publish_to_shared_image_gallery_test.go index ebcc681f8..d11fb052b 100644 --- a/builder/azure/arm/step_publish_to_shared_image_gallery_test.go +++ b/builder/azure/arm/step_publish_to_shared_image_gallery_test.go @@ -10,7 +10,7 @@ import ( func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) { var testSubject = &StepPublishToSharedImageGallery{ - publish: func(context.Context, string, string, string, string, string, []string, string, map[string]*string) (string, error) { + publish: func(context.Context, string, string, string, string, string, []string, string, bool, int32, string, map[string]*string) (string, error) { return "test", nil }, say: func(message string) {}, @@ -31,7 +31,7 @@ func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) { func TestStepPublishToSharedImageGalleryShouldPublishForManagedImageWithSig(t *testing.T) { var testSubject = &StepPublishToSharedImageGallery{ - publish: func(context.Context, string, string, string, string, string, []string, string, map[string]*string) (string, error) { + publish: func(context.Context, string, string, string, string, string, []string, string, bool, int32, string, map[string]*string) (string, error) { return "", nil }, say: func(message string) {}, diff --git a/builder/azure/common/constants/stateBag.go b/builder/azure/common/constants/stateBag.go index c68afd508..0bf0ad1ae 100644 --- a/builder/azure/common/constants/stateBag.go +++ b/builder/azure/common/constants/stateBag.go @@ -9,6 +9,13 @@ const ( Thumbprint string = "thumbprint" Ui string = "ui" ) + +// Default replica count for image versions in shared image gallery +const ( + SharedImageGalleryImageVersionDefaultMinReplicaCount int32 = 1 + SharedImageGalleryImageVersionDefaultMaxReplicaCount int32 = 10 +) + const ( ArmCaptureTemplate string = "arm.CaptureTemplate" ArmComputeName string = "arm.ComputeName" @@ -30,18 +37,21 @@ const ( ArmVirtualMachineCaptureParameters string = "arm.VirtualMachineCaptureParameters" ArmIsExistingResourceGroup string = "arm.IsExistingResourceGroup" - ArmIsManagedImage string = "arm.IsManagedImage" - ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName" - ArmManagedImageLocation string = "arm.ManagedImageLocation" - ArmManagedImageName string = "arm.ManagedImageName" - ArmManagedImageSigPublishResourceGroup string = "arm.ManagedImageSigPublishResourceGroup" - ArmManagedImageSharedGalleryName string = "arm.ManagedImageSharedGalleryName" - ArmManagedImageSharedGalleryImageName string = "arm.ManagedImageSharedGalleryImageName" - ArmManagedImageSharedGalleryImageVersion string = "arm.ManagedImageSharedGalleryImageVersion" - ArmManagedImageSharedGalleryReplicationRegions string = "arm.ManagedImageSharedGalleryReplicationRegions" - ArmManagedImageSharedGalleryId string = "arm.ArmManagedImageSharedGalleryId" - ArmManagedImageSubscription string = "arm.ArmManagedImageSubscription" - ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete" - ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName" - ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix" + ArmIsManagedImage string = "arm.IsManagedImage" + ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName" + ArmManagedImageLocation string = "arm.ManagedImageLocation" + ArmManagedImageName string = "arm.ManagedImageName" + ArmManagedImageSigPublishResourceGroup string = "arm.ManagedImageSigPublishResourceGroup" + ArmManagedImageSharedGalleryName string = "arm.ManagedImageSharedGalleryName" + ArmManagedImageSharedGalleryImageName string = "arm.ManagedImageSharedGalleryImageName" + ArmManagedImageSharedGalleryImageVersion string = "arm.ManagedImageSharedGalleryImageVersion" + ArmManagedImageSharedGalleryReplicationRegions string = "arm.ManagedImageSharedGalleryReplicationRegions" + ArmManagedImageSharedGalleryId string = "arm.ArmManagedImageSharedGalleryId" + ArmManagedImageSharedGalleryImageVersionEndOfLifeDate string = "arm.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate" + ArmManagedImageSharedGalleryImageVersionReplicaCount string = "arm.ArmManagedImageSharedGalleryImageVersionReplicaCount" + ArmManagedImageSharedGalleryImageVersionExcludeFromLatest string = "arm.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest" + ArmManagedImageSubscription string = "arm.ArmManagedImageSubscription" + ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete" + ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName" + ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix" ) diff --git a/go.mod b/go.mod index d6f811f73..299a7f14d 100644 --- a/go.mod +++ b/go.mod @@ -81,7 +81,7 @@ require ( github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl/v2 v2.0.0 - github.com/hashicorp/hcl2 v0.0.0-20191002203319-fb75b3253c80 + github.com/hashicorp/hcl2 v0.0.0-20191002203319-fb75b3253c80 // indirect github.com/hashicorp/serf v0.8.2 // indirect github.com/hashicorp/vault v1.1.0 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d diff --git a/website/source/partials/builder/azure/arm/_Config-not-required.html.md b/website/source/partials/builder/azure/arm/_Config-not-required.html.md index 02a0f9a91..01ab45847 100644 --- a/website/source/partials/builder/azure/arm/_Config-not-required.html.md +++ b/website/source/partials/builder/azure/arm/_Config-not-required.html.md @@ -40,6 +40,16 @@ its default of "60m" (valid time units include `s` for seconds, `m` for minutes, and `h` for hours.) +- `shared_gallery_image_version_end_of_life_date` (string) - The end of life date (2006-01-02T15:04:05.99Z) of the gallery Image Version. This property + can be used for decommissioning purposes. + +- `shared_image_gallery_replica_count` (int32) - The number of replicas of the Image Version to be created per region. This + property would take effect for a region when regionalReplicaCount is not specified. + Replica count must be between 1 and 10. + +- `shared_gallery_image_version_exclude_from_latest` (bool) - If set to true, Virtual Machines deployed from the latest version of the + Image Definition won't use this Image Version. + - `image_version` (string) - Specify a specific version of an OS to boot from. Defaults to `latest`. There may be a difference in versions available across regions due to image synchronization latency. To ensure a consistent