Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_shared_image & azurerm_shared_image_version - support for specialized images by setting generalized to false #7277

Merged
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4d049ae
Add os_state to shared_image resource and data source. Added new tests
ArcturusZhang May 29, 2020
79e0b71
Update shared image version resource and data source
ArcturusZhang May 29, 2020
d54ed99
Resolve comments
ArcturusZhang Jun 1, 2020
736ec21
Fixing the style
ArcturusZhang Jun 1, 2020
359e13e
managed_image_id and os_disk_snapshot conflicts with each other
ArcturusZhang Jun 1, 2020
7106953
Merge branch 'specialized-custom-image-shared-image-version' into spe…
ArcturusZhang Jun 1, 2020
be5708a
Remove useless comments
ArcturusZhang Jun 1, 2020
f12a65f
fmt and clean up
ArcturusZhang Jun 1, 2020
a8297b2
os disk snapshot id should be forcenew
ArcturusZhang Jun 1, 2020
ba8ec3c
Some update on schema
ArcturusZhang Jun 2, 2020
8bd5ce1
Merge remote-tracking branch 'origin/master' into specialized-custom-…
ArcturusZhang Jun 2, 2020
7568285
Removed dead code
ArcturusZhang Jun 2, 2020
a840d87
Updated docs accordingly
ArcturusZhang Jun 2, 2020
a662525
Merge remote-tracking branch 'origin/master' into specialized-custom-…
ArcturusZhang Jun 10, 2020
331da64
Use parsing for shared image version Read and Delete
ArcturusZhang Jun 10, 2020
f505331
Add a dummy test to revoke the SAS in order to let the snapshot can b…
ArcturusZhang Jun 10, 2020
d4be0a0
Removed some test code
ArcturusZhang Jun 10, 2020
a500fd1
Support for assigning VM ID to managed_image_id
ArcturusZhang Jun 12, 2020
397821c
Merge remote-tracking branch 'origin/master' into specialized-custom-…
ArcturusZhang Jun 15, 2020
60e7eb9
goimported
ArcturusZhang Jun 15, 2020
0cb9fe0
Resolve comments
ArcturusZhang Jun 28, 2020
a3fa055
Update website/docs/r/shared_image.html.markdown
katbyte Jun 29, 2020
0fa49fd
Update website/docs/d/shared_image.html.markdown
katbyte Jun 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions azurerm/internal/services/compute/shared_image_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func dataSourceArmSharedImage() *schema.Resource {
Computed: true,
},

"generalized": {
Type: schema.TypeBool,
Computed: true,
},

"hyper_v_generation": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -125,12 +130,12 @@ func dataSourceArmSharedImageRead(d *schema.ResourceData, meta interface{}) erro
d.Set("description", props.Description)
d.Set("eula", props.Eula)
d.Set("os_type", string(props.OsType))
d.Set("generalized", props.OsState != compute.Specialized)
d.Set("hyper_v_generation", string(props.HyperVGeneration))
d.Set("privacy_statement_uri", props.PrivacyStatementURI)
d.Set("release_note_uri", props.ReleaseNoteURI)

flattenedIdentifier := flattenGalleryImageDataSourceIdentifier(props.Identifier)
if err := d.Set("identifier", flattenedIdentifier); err != nil {
if err := d.Set("identifier", flattenGalleryImageDataSourceIdentifier(props.Identifier)); err != nil {
return fmt.Errorf("Error setting `identifier`: %+v", err)
}
}
Expand Down
116 changes: 60 additions & 56 deletions azurerm/internal/services/compute/shared_image_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)
Expand All @@ -25,9 +27,11 @@ func resourceArmSharedImage() *schema.Resource {
Read: resourceArmSharedImageRead,
Update: resourceArmSharedImageCreateUpdate,
Delete: resourceArmSharedImageDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error {
_, err := parse.SharedImageID(id)
return err
}),

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Expand Down Expand Up @@ -58,12 +62,20 @@ func resourceArmSharedImage() *schema.Resource {
"os_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(compute.Linux),
string(compute.Windows),
}, false),
},

"generalized": {
Type: schema.TypeBool,
Optional: true,
Default: true,
ForceNew: true,
},

"hyper_v_generation": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -132,16 +144,6 @@ func resourceArmSharedImageCreateUpdate(d *schema.ResourceData, meta interface{}
name := d.Get("name").(string)
galleryName := d.Get("gallery_name").(string)
resourceGroup := d.Get("resource_group_name").(string)
location := azure.NormalizeLocation(d.Get("location").(string))
description := d.Get("description").(string)
hyperVGeneration := d.Get("hyper_v_generation").(string)

eula := d.Get("eula").(string)
privacyStatementUri := d.Get("privacy_statement_uri").(string)
releaseNoteURI := d.Get("release_note_uri").(string)

osType := d.Get("os_type").(string)
t := d.Get("tags").(map[string]interface{})

if d.IsNewResource() {
existing, err := client.Get(ctx, resourceGroup, galleryName, name)
Expand All @@ -156,21 +158,24 @@ func resourceArmSharedImageCreateUpdate(d *schema.ResourceData, meta interface{}
}
}

identifier := expandGalleryImageIdentifier(d)

image := compute.GalleryImage{
Location: utils.String(location),
Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))),
GalleryImageProperties: &compute.GalleryImageProperties{
Description: utils.String(description),
Eula: utils.String(eula),
Identifier: identifier,
PrivacyStatementURI: utils.String(privacyStatementUri),
ReleaseNoteURI: utils.String(releaseNoteURI),
OsType: compute.OperatingSystemTypes(osType),
OsState: compute.Generalized,
HyperVGeneration: compute.HyperVGeneration(hyperVGeneration),
Description: utils.String(d.Get("description").(string)),
Eula: utils.String(d.Get("eula").(string)),
Identifier: expandGalleryImageIdentifier(d),
PrivacyStatementURI: utils.String(d.Get("privacy_statement_uri").(string)),
ReleaseNoteURI: utils.String(d.Get("release_note_uri").(string)),
OsType: compute.OperatingSystemTypes(d.Get("os_type").(string)),
HyperVGeneration: compute.HyperVGeneration(d.Get("hyper_v_generation").(string)),
},
Tags: tags.Expand(t),
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

if d.Get("generalized").(bool) {
image.GalleryImageProperties.OsState = compute.Generalized
} else {
image.GalleryImageProperties.OsState = compute.Specialized
}

future, err := client.CreateOrUpdate(ctx, resourceGroup, galleryName, name, image)
Expand Down Expand Up @@ -201,29 +206,25 @@ func resourceArmSharedImageRead(d *schema.ResourceData, meta interface{}) error
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.SharedImageID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
galleryName := id.Path["galleries"]
name := id.Path["images"]

resp, err := client.Get(ctx, resourceGroup, galleryName, name)
resp, err := client.Get(ctx, id.ResourceGroup, id.Gallery, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] Shared Image %q (Gallery %q / Resource Group %q) was not found - removing from state", name, galleryName, resourceGroup)
log.Printf("[DEBUG] Shared Image %q (Gallery %q / Resource Group %q) was not found - removing from state", id.Name, id.Gallery, id.ResourceGroup)
d.SetId("")
return nil
}

return fmt.Errorf("Error making Read request on Shared Image %q (Gallery %q / Resource Group %q): %+v", name, galleryName, resourceGroup, err)
return fmt.Errorf("Error making Read request on Shared Image %q (Gallery %q / Resource Group %q): %+v", id.Name, id.Gallery, id.ResourceGroup, err)
}

d.Set("name", name)
d.Set("gallery_name", galleryName)
d.Set("resource_group_name", resourceGroup)
d.Set("name", id.Name)
d.Set("gallery_name", id.Gallery)
d.Set("resource_group_name", id.ResourceGroup)
if location := resp.Location; location != nil {
d.Set("location", azure.NormalizeLocation(*location))
}
Expand All @@ -232,12 +233,12 @@ func resourceArmSharedImageRead(d *schema.ResourceData, meta interface{}) error
d.Set("description", props.Description)
d.Set("eula", props.Eula)
d.Set("os_type", string(props.OsType))
d.Set("generalized", props.OsState != compute.Specialized)
d.Set("hyper_v_generation", string(props.HyperVGeneration))
d.Set("privacy_statement_uri", props.PrivacyStatementURI)
d.Set("release_note_uri", props.ReleaseNoteURI)

flattenedIdentifier := flattenGalleryImageIdentifier(props.Identifier)
if err := d.Set("identifier", flattenedIdentifier); err != nil {
if err := d.Set("identifier", flattenGalleryImageIdentifier(props.Identifier)); err != nil {
return fmt.Errorf("Error setting `identifier`: %+v", err)
}
}
Expand All @@ -250,42 +251,38 @@ func resourceArmSharedImageDelete(d *schema.ResourceData, meta interface{}) erro
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.SharedImageID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
galleryName := id.Path["galleries"]
name := id.Path["images"]

future, err := client.Delete(ctx, resourceGroup, galleryName, name)
future, err := client.Delete(ctx, id.ResourceGroup, id.Gallery, id.Name)
if err != nil {
return fmt.Errorf("deleting Shared Image %q (Gallery %q / Resource Group %q): %+v", name, galleryName, resourceGroup, err)
return fmt.Errorf("deleting Shared Image %q (Gallery %q / Resource Group %q): %+v", id.Name, id.Gallery, id.ResourceGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("failed to wait for deleting Shared Image %q (Gallery %q / Resource Group %q): %+v", name, galleryName, resourceGroup, err)
return fmt.Errorf("failed to wait for deleting Shared Image %q (Gallery %q / Resource Group %q): %+v", id.Name, id.Gallery, id.ResourceGroup, err)
}

log.Printf("[DEBUG] Waiting for Shared Image %q (Gallery %q / Resource Group %q) to be eventually deleted", name, galleryName, resourceGroup)
log.Printf("[DEBUG] Waiting for Shared Image %q (Gallery %q / Resource Group %q) to be eventually deleted", id.Name, id.Gallery, id.ResourceGroup)
stateConf := &resource.StateChangeConf{
Pending: []string{"Exists"},
Target: []string{"NotFound"},
Refresh: sharedImageDeleteStateRefreshFunc(ctx, client, resourceGroup, name, galleryName),
Refresh: sharedImageDeleteStateRefreshFunc(ctx, client, id.ResourceGroup, id.Gallery, id.Name),
MinTimeout: 10 * time.Second,
ContinuousTargetOccurence: 10,
Timeout: d.Timeout(schema.TimeoutDelete),
}

if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf("failed to wait for Shared Image %q (Gallery %q / Resource Group %q) to be deleted: %+v", name, galleryName, resourceGroup, err)
return fmt.Errorf("failed to wait for Shared Image %q (Gallery %q / Resource Group %q) to be deleted: %+v", id.Name, id.Gallery, id.ResourceGroup, err)
}

return nil
}

func sharedImageDeleteStateRefreshFunc(ctx context.Context, client *compute.GalleryImagesClient, resourceGroupName string, imageName string, galleryName string) resource.StateRefreshFunc {
func sharedImageDeleteStateRefreshFunc(ctx context.Context, client *compute.GalleryImagesClient, resourceGroupName string, galleryName string, imageName string) resource.StateRefreshFunc {
// The resource Shared Image depends on the resource Shared Image Gallery.
// Although the delete API returns 404 which means the Shared Image resource has been deleted.
// Then it tries to immediately delete Shared Image Gallery but it still throws error `Can not delete resource before nested resources are deleted.`
Expand Down Expand Up @@ -325,19 +322,26 @@ func flattenGalleryImageIdentifier(input *compute.GalleryImageIdentifier) []inte
return []interface{}{}
}

result := make(map[string]interface{})

offer := ""
if input.Offer != nil {
result["offer"] = *input.Offer
offer = *input.Offer
}

publisher := ""
if input.Publisher != nil {
result["publisher"] = *input.Publisher
publisher = *input.Publisher
}

sku := ""
if input.Sku != nil {
result["sku"] = *input.Sku
sku = *input.Sku
}

return []interface{}{result}
return []interface{}{
map[string]interface{}{
"offer": offer,
"publisher": publisher,
"sku": sku,
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func dataSourceArmSharedImageVersion() *schema.Resource {
Computed: true,
},

"os_disk_snapshot_id": {
Type: schema.TypeString,
Computed: true,
},

"target_region": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -113,8 +118,7 @@ func dataSourceArmSharedImageVersionRead(d *schema.ResourceData, meta interface{
if profile := props.PublishingProfile; profile != nil {
d.Set("exclude_from_latest", profile.ExcludeFromLatest)

flattenedRegions := flattenSharedImageVersionDataSourceTargetRegions(profile.TargetRegions)
if err := d.Set("target_region", flattenedRegions); err != nil {
if err := d.Set("target_region", flattenSharedImageVersionDataSourceTargetRegions(profile.TargetRegions)); err != nil {
return fmt.Errorf("Error setting `target_region`: %+v", err)
}
}
Expand All @@ -123,6 +127,12 @@ func dataSourceArmSharedImageVersionRead(d *schema.ResourceData, meta interface{
if source := profile.Source; source != nil {
d.Set("managed_image_id", source.ID)
}

osDiskSnapShotID := ""
if profile.OsDiskImage != nil && profile.OsDiskImage.Source != nil && profile.OsDiskImage.Source.ID != nil {
osDiskSnapShotID = *profile.OsDiskImage.Source.ID
}
d.Set("os_disk_snapshot_id", osDiskSnapShotID)
}
}

Expand Down
Loading