azure: arm builder: adding keep_os_disk parameter to control OS disk deletion.

keep_os_disk: auto generated help
azure: arm builder: add disk os to artifact
azure: arm builder: fmt'ed artifact_test.go
This commit is contained in:
Contigo Red 2020-10-05 21:54:03 +03:00 committed by Megan Marsh
parent 95ed4443bb
commit 82a1f017aa
8 changed files with 166 additions and 29 deletions

View File

@ -46,8 +46,8 @@ type Artifact struct {
StateData map[string]interface{} StateData map[string]interface{}
} }
func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix string, generatedData map[string]interface{}) (*Artifact, error) { func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix string, generatedData map[string]interface{}, keepOSDisk bool, template *CaptureTemplate, getSasUrl func(name string) string) (*Artifact, error) {
return &Artifact{ res := Artifact{
ManagedImageResourceGroupName: resourceGroup, ManagedImageResourceGroupName: resourceGroup,
ManagedImageName: name, ManagedImageName: name,
ManagedImageLocation: location, ManagedImageLocation: location,
@ -56,7 +56,27 @@ func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSn
ManagedImageOSDiskSnapshotName: osDiskSnapshotName, ManagedImageOSDiskSnapshotName: osDiskSnapshotName,
ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix, ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix,
StateData: generatedData, StateData: generatedData,
}, nil }
if keepOSDisk {
if template == nil {
return nil, fmt.Errorf("nil capture template")
}
if len(template.Resources) != 1 {
return nil, fmt.Errorf("malformed capture template, expected one resource")
}
vhdUri, err := url.Parse(template.Resources[0].Properties.StorageProfile.OSDisk.Image.Uri)
if err != nil {
return nil, err
}
res.OSDiskUri = vhdUri.String()
res.OSDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(vhdUri))
}
return &res, nil
} }
func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix, destinationSharedImageGalleryId string, generatedData map[string]interface{}) (*Artifact, error) { func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix, destinationSharedImageGalleryId string, generatedData map[string]interface{}) (*Artifact, error) {
@ -198,6 +218,12 @@ func (a *Artifact) String() string {
if a.ManagedImageSharedImageGalleryId != "" { if a.ManagedImageSharedImageGalleryId != "" {
buf.WriteString(fmt.Sprintf("ManagedImageSharedImageGalleryId: %s\n", a.ManagedImageSharedImageGalleryId)) buf.WriteString(fmt.Sprintf("ManagedImageSharedImageGalleryId: %s\n", a.ManagedImageSharedImageGalleryId))
} }
if a.OSDiskUri != "" {
buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri))
}
if a.OSDiskUriReadOnlySas != "" {
buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas))
}
} else { } else {
buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation)) buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation))
buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri)) buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri))

View File

@ -46,7 +46,24 @@ func TestArtifactIdVHD(t *testing.T) {
} }
func TestArtifactIDManagedImage(t *testing.T) { func TestArtifactIDManagedImage(t *testing.T) {
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", generatedData()) template := CaptureTemplate{
Resources: []CaptureResources{
{
Properties: CaptureProperties{
StorageProfile: CaptureStorageProfile{
OSDisk: CaptureDisk{
Image: CaptureUri{
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
},
},
},
},
Location: "southcentralus",
},
},
}
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", generatedData(), false, &template, getFakeSasUrl)
if err != nil { if err != nil {
t.Fatalf("err=%s", err) t.Fatalf("err=%s", err)
} }
@ -69,7 +86,24 @@ ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix
} }
func TestArtifactIDManagedImageWithoutOSDiskSnapshotName(t *testing.T) { func TestArtifactIDManagedImageWithoutOSDiskSnapshotName(t *testing.T) {
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "", "fakeDataDiskSnapshotPrefix", generatedData()) template := CaptureTemplate{
Resources: []CaptureResources{
{
Properties: CaptureProperties{
StorageProfile: CaptureStorageProfile{
OSDisk: CaptureDisk{
Image: CaptureUri{
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
},
},
},
},
Location: "southcentralus",
},
},
}
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "", "fakeDataDiskSnapshotPrefix", generatedData(), false, &template, getFakeSasUrl)
if err != nil { if err != nil {
t.Fatalf("err=%s", err) t.Fatalf("err=%s", err)
} }
@ -91,7 +125,24 @@ ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix
} }
func TestArtifactIDManagedImageWithoutDataDiskSnapshotPrefix(t *testing.T) { func TestArtifactIDManagedImageWithoutDataDiskSnapshotPrefix(t *testing.T) {
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData()) template := CaptureTemplate{
Resources: []CaptureResources{
{
Properties: CaptureProperties{
StorageProfile: CaptureStorageProfile{
OSDisk: CaptureDisk{
Image: CaptureUri{
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
},
},
},
},
Location: "southcentralus",
},
},
}
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData(), false, &template, getFakeSasUrl)
if err != nil { if err != nil {
t.Fatalf("err=%s", err) t.Fatalf("err=%s", err)
} }
@ -112,6 +163,47 @@ ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName
} }
} }
func TestArtifactIDManagedImageWithKeepingTheOSDisk(t *testing.T) {
template := CaptureTemplate{
Resources: []CaptureResources{
{
Properties: CaptureProperties{
StorageProfile: CaptureStorageProfile{
OSDisk: CaptureDisk{
Image: CaptureUri{
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
},
},
},
},
Location: "southcentralus",
},
},
}
artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData(), true, &template, getFakeSasUrl)
if err != nil {
t.Fatalf("err=%s", err)
}
expected := `Azure.ResourceManagement.VMImage:
OSType: Linux
ManagedImageResourceGroupName: fakeResourceGroup
ManagedImageName: fakeName
ManagedImageId: fakeID
ManagedImageLocation: fakeLocation
ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName
OSDiskUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd
OSDiskUriReadOnlySas: SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd
`
result := artifact.String()
if result != expected {
t.Fatalf("bad: %s", result)
}
}
func TestArtifactIDManagedImageWithSharedImageGalleryId(t *testing.T) { func TestArtifactIDManagedImageWithSharedImageGalleryId(t *testing.T) {
artifact, err := NewManagedImageArtifactWithSIGAsDestination("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", "fakeSharedImageGallery", generatedData()) artifact, err := NewManagedImageArtifactWithSIGAsDestination("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", "fakeSharedImageGallery", generatedData())
if err != nil { if err != nil {

View File

@ -296,6 +296,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
return nil, errors.New("Build was halted.") return nil, errors.New("Build was halted.")
} }
getSasUrlFunc := func(name string) string {
blob := azureClient.BlobStorageClient.GetContainerReference(DefaultSasBlobContainer).GetBlobReference(name)
options := storage.BlobSASOptions{}
options.BlobServiceSASPermissions.Read = true
options.Expiry = time.Now().AddDate(0, 1, 0).UTC() // one month
sasUrl, _ := blob.GetSASURI(options)
return sasUrl
}
generatedData := map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")} generatedData := map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")}
if b.config.isManagedImage() { if b.config.isManagedImage() {
managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s",
@ -310,26 +319,23 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
b.config.ManagedImageDataDiskSnapshotPrefix, b.config.ManagedImageDataDiskSnapshotPrefix,
b.stateBag.Get(constants.ArmManagedImageSharedGalleryId).(string), b.stateBag.Get(constants.ArmManagedImageSharedGalleryId).(string),
generatedData) generatedData)
} else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok {
return NewManagedImageArtifact(b.config.OSType,
b.config.ManagedImageResourceGroupName,
b.config.ManagedImageName,
b.config.Location,
managedImageID,
b.config.ManagedImageOSDiskSnapshotName,
b.config.ManagedImageDataDiskSnapshotPrefix,
generatedData,
b.stateBag.Get(constants.ArmKeepOSDisk).(bool),
template.(*CaptureTemplate),
getSasUrlFunc)
} }
return NewManagedImageArtifact(b.config.OSType,
b.config.ManagedImageResourceGroupName,
b.config.ManagedImageName,
b.config.Location,
managedImageID,
b.config.ManagedImageOSDiskSnapshotName,
b.config.ManagedImageDataDiskSnapshotPrefix,
generatedData)
} else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { } else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok {
return NewArtifact( return NewArtifact(
template.(*CaptureTemplate), template.(*CaptureTemplate),
func(name string) string { getSasUrlFunc,
blob := azureClient.BlobStorageClient.GetContainerReference(DefaultSasBlobContainer).GetBlobReference(name)
options := storage.BlobSASOptions{}
options.BlobServiceSASPermissions.Read = true
options.Expiry = time.Now().AddDate(0, 1, 0).UTC() // one month
sasUrl, _ := blob.GetSASURI(options)
return sasUrl
},
b.config.OSType, b.config.OSType,
generatedData) generatedData)
} }
@ -425,6 +431,7 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
stateBag.Put(constants.ArmManagedImageOSDiskSnapshotName, b.config.ManagedImageOSDiskSnapshotName) stateBag.Put(constants.ArmManagedImageOSDiskSnapshotName, b.config.ManagedImageOSDiskSnapshotName)
stateBag.Put(constants.ArmManagedImageDataDiskSnapshotPrefix, b.config.ManagedImageDataDiskSnapshotPrefix) stateBag.Put(constants.ArmManagedImageDataDiskSnapshotPrefix, b.config.ManagedImageDataDiskSnapshotPrefix)
stateBag.Put(constants.ArmAsyncResourceGroupDelete, b.config.AsyncResourceGroupDelete) stateBag.Put(constants.ArmAsyncResourceGroupDelete, b.config.AsyncResourceGroupDelete)
stateBag.Put(constants.ArmKeepOSDisk, b.config.KeepOSDisk)
if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" {
stateBag.Put(constants.ArmManagedImageSigPublishResourceGroup, b.config.SharedGalleryDestination.SigDestinationResourceGroup) stateBag.Put(constants.ArmManagedImageSigPublishResourceGroup, b.config.SharedGalleryDestination.SigDestinationResourceGroup)

View File

@ -279,6 +279,10 @@ type Config struct {
// disk(s) is created with the same prefix as this value before the VM is // disk(s) is created with the same prefix as this value before the VM is
// captured. // captured.
ManagedImageDataDiskSnapshotPrefix string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false"` ManagedImageDataDiskSnapshotPrefix string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false"`
// If
// keep_os_disk is set, the OS disk is not deleted.
// The default is false.
KeepOSDisk bool `mapstructure:"keep_os_disk" required:"false"`
// Store the image in zone-resilient storage. You need to create it in a // Store the image in zone-resilient storage. You need to create it in a
// region that supports [availability // region that supports [availability
// zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview). // zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview).

View File

@ -52,6 +52,7 @@ type FlatConfig struct {
ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type" hcl:"managed_image_storage_account_type"` ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type" hcl:"managed_image_storage_account_type"`
ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name" hcl:"managed_image_os_disk_snapshot_name"` ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name" hcl:"managed_image_os_disk_snapshot_name"`
ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix" hcl:"managed_image_data_disk_snapshot_prefix"` ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix" hcl:"managed_image_data_disk_snapshot_prefix"`
KeepOSDisk *bool `mapstructure:"keep_os_disk" required:"false" cty:"keep_os_disk" hcl:"keep_os_disk"`
ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient" hcl:"managed_image_zone_resilient"` ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient" hcl:"managed_image_zone_resilient"`
AzureTags map[string]string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"` AzureTags map[string]string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"`
AzureTag []config.FlatNameValue `mapstructure:"azure_tag" required:"false" cty:"azure_tag" hcl:"azure_tag"` AzureTag []config.FlatNameValue `mapstructure:"azure_tag" required:"false" cty:"azure_tag" hcl:"azure_tag"`
@ -183,6 +184,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"managed_image_storage_account_type": &hcldec.AttrSpec{Name: "managed_image_storage_account_type", Type: cty.String, Required: false}, "managed_image_storage_account_type": &hcldec.AttrSpec{Name: "managed_image_storage_account_type", Type: cty.String, Required: false},
"managed_image_os_disk_snapshot_name": &hcldec.AttrSpec{Name: "managed_image_os_disk_snapshot_name", Type: cty.String, Required: false}, "managed_image_os_disk_snapshot_name": &hcldec.AttrSpec{Name: "managed_image_os_disk_snapshot_name", Type: cty.String, Required: false},
"managed_image_data_disk_snapshot_prefix": &hcldec.AttrSpec{Name: "managed_image_data_disk_snapshot_prefix", Type: cty.String, Required: false}, "managed_image_data_disk_snapshot_prefix": &hcldec.AttrSpec{Name: "managed_image_data_disk_snapshot_prefix", Type: cty.String, Required: false},
"keep_os_disk": &hcldec.AttrSpec{Name: "keep_os_disk", Type: cty.Bool, Required: false},
"managed_image_zone_resilient": &hcldec.AttrSpec{Name: "managed_image_zone_resilient", Type: cty.Bool, Required: false}, "managed_image_zone_resilient": &hcldec.AttrSpec{Name: "managed_image_zone_resilient", Type: cty.Bool, Required: false},
"azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false}, "azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false},
"azure_tag": &hcldec.BlockListSpec{TypeName: "azure_tag", Nested: hcldec.ObjectSpec((*config.FlatNameValue)(nil).HCL2Spec())}, "azure_tag": &hcldec.BlockListSpec{TypeName: "azure_tag", Nested: hcldec.ObjectSpec((*config.FlatNameValue)(nil).HCL2Spec())},

View File

@ -92,13 +92,14 @@ func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
"Error: %s", computeName, err)) "Error: %s", computeName, err))
return return
} }
if !state.Get(constants.ArmKeepOSDisk).(bool) {
ui.Say(fmt.Sprintf(" Deleting -> %s : '%s'", imageType, imageName)) ui.Say(fmt.Sprintf(" Deleting -> %s : '%s'", imageType, imageName))
err = s.deleteDisk(context.TODO(), imageType, imageName, resourceGroupName) err = s.deleteDisk(context.TODO(), imageType, imageName, resourceGroupName)
if err != nil { if err != nil {
ui.Error(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+ ui.Error(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+
"Name: %s\n"+ "Name: %s\n"+
"Error: %s", imageName, err)) "Error: %s", imageName, err))
}
} }
} }

View File

@ -54,4 +54,5 @@ const (
ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete" ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete"
ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName" ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName"
ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix" ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix"
ArmKeepOSDisk string = "arm.KeepOSDisk"
) )

View File

@ -133,6 +133,10 @@
disk(s) is created with the same prefix as this value before the VM is disk(s) is created with the same prefix as this value before the VM is
captured. captured.
- `keep_os_disk` (bool) - If
keep_os_disk is set, the OS disk is not deleted.
The default is false.
- `managed_image_zone_resilient` (bool) - Store the image in zone-resilient storage. You need to create it in a - `managed_image_zone_resilient` (bool) - Store the image in zone-resilient storage. You need to create it in a
region that supports [availability region that supports [availability
zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview). zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview).