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

resource/aws_appstream_stack: Fix panic on read #27257

Merged
merged 4 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .changelog/27257.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_appstream_stack: Fix panic with `application_settings`.
```

```release-note:enhancement
resource/aws_appstream_stack: Add validation for `application_settings`.
```
107 changes: 70 additions & 37 deletions internal/service/appstream/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package appstream
import (
"bytes"
"context"
"errors"
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/appstream"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand All @@ -19,6 +22,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

var (
Expand Down Expand Up @@ -66,11 +70,12 @@ func ResourceStack() *schema.Resource {
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Optional: true,
Required: true,
},
"settings_group": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 100),
},
},
},
Expand Down Expand Up @@ -182,6 +187,53 @@ func ResourceStack() *schema.Resource {
"tags": tftags.TagsSchemaForceNew(),
"tags_all": tftags.TagsSchemaComputed(),
},

CustomizeDiff: customdiff.All(
verify.SetTagsDiff,
func(_ context.Context, d *schema.ResourceDiff, meta interface{}) error {
if d.Id() == "" {
return nil
}

rawConfig := d.GetRawConfig()
configApplicationSettings := rawConfig.GetAttr("application_settings")
if configApplicationSettings.IsKnown() && !configApplicationSettings.IsNull() && configApplicationSettings.LengthInt() > 0 {
return nil
}

rawState := d.GetRawState()
stateApplicationSettings := rawState.GetAttr("application_settings")
if stateApplicationSettings.IsKnown() && !stateApplicationSettings.IsNull() && stateApplicationSettings.LengthInt() > 0 {
setting := stateApplicationSettings.Index(cty.NumberIntVal(0))
if setting.IsKnown() && !setting.IsNull() {
enabled := setting.GetAttr("enabled")
if enabled.IsKnown() && !enabled.IsNull() && enabled.True() {
// Trigger a diff
return d.SetNew("application_settings", []map[string]any{
{
"enabled": false,
"settings_group": "",
},
})
}
}
}

return nil
},
func(_ context.Context, d *schema.ResourceDiff, meta interface{}) error {
_, enabled := d.GetOk("application_settings.0.enabled")
v, sg := d.GetOk("application_settings.0.settings_group")
log.Print(v)

if enabled && !sg {
return errors.New("application_settings.settings_group must be set when application_settings.enabled is true")
} else if !enabled && sg {
return errors.New("application_settings.settings_group must not be set when application_settings.enabled is false")
}
return nil
},
),
}
}

Expand Down Expand Up @@ -284,14 +336,14 @@ func resourceStackRead(ctx context.Context, d *schema.ResourceData, meta interfa
return diag.FromErr(fmt.Errorf("error setting `%s` for AppStream Stack (%s): %w", "access_endpoints", d.Id(), err))
}
if err = d.Set("application_settings", flattenApplicationSettings(v.ApplicationSettings)); err != nil {
return diag.FromErr(fmt.Errorf("error setting `%s` for AppStream Stack (%s): %w", "user_settings", d.Id(), err))
return diag.FromErr(fmt.Errorf("error setting `%s` for AppStream Stack (%s): %w", "application_settings", d.Id(), err))
}
d.Set("arn", v.Arn)
d.Set("created_time", aws.TimeValue(v.CreatedTime).Format(time.RFC3339))
d.Set("description", v.Description)
d.Set("display_name", v.DisplayName)
if err = d.Set("embed_host_domains", flex.FlattenStringList(v.EmbedHostDomains)); err != nil {
return diag.FromErr(fmt.Errorf("error setting `%s` for AppStream Stack (%s): %w", "user_settings", d.Id(), err))
return diag.FromErr(fmt.Errorf("error setting `%s` for AppStream Stack (%s): %w", "embed_host_domains", d.Id(), err))
}
d.Set("feedback_url", v.FeedbackURL)
d.Set("name", v.Name)
Expand Down Expand Up @@ -335,7 +387,7 @@ func resourceStackUpdate(ctx context.Context, d *schema.ResourceData, meta inter
}

if d.HasChange("application_settings") {
input.ApplicationSettings = expandApplicationSettings(d.Get("application_settings").(*schema.Set).List())
input.ApplicationSettings = expandApplicationSettings(d.Get("application_settings").([]interface{}))
}

if d.HasChange("description") {
Expand Down Expand Up @@ -474,15 +526,17 @@ func flattenAccessEndpoints(apiObjects []*appstream.AccessEndpoint) []map[string
return tfList
}

func expandApplicationSetting(tfMap map[string]interface{}) *appstream.ApplicationSettings {
if tfMap == nil {
return nil
func expandApplicationSettings(tfList []interface{}) *appstream.ApplicationSettings {
if len(tfList) == 0 {
return &appstream.ApplicationSettings{
Enabled: aws.Bool(false),
}
}

apiObject := &appstream.ApplicationSettings{}
tfMap := tfList[0].(map[string]interface{})

if v, ok := tfMap["enabled"]; ok {
apiObject.Enabled = aws.Bool(v.(bool))
apiObject := &appstream.ApplicationSettings{
Enabled: aws.Bool(tfMap["enabled"].(bool)),
}
if v, ok := tfMap["settings_group"]; ok {
apiObject.SettingsGroup = aws.String(v.(string))
Expand All @@ -491,36 +545,15 @@ func expandApplicationSetting(tfMap map[string]interface{}) *appstream.Applicati
return apiObject
}

func expandApplicationSettings(tfList []interface{}) *appstream.ApplicationSettings {
if len(tfList) == 0 {
return nil
}

var apiObject *appstream.ApplicationSettings

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

apiObject = expandApplicationSetting(tfMap)
}

return apiObject
}

func flattenApplicationSetting(apiObject *appstream.ApplicationSettingsResponse) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}
tfMap["enabled"] = aws.BoolValue(apiObject.Enabled)
tfMap["settings_group"] = aws.StringValue(apiObject.SettingsGroup)

return tfMap
return map[string]interface{}{
"enabled": aws.BoolValue(apiObject.Enabled),
"settings_group": aws.StringValue(apiObject.SettingsGroup),
}
}

func flattenApplicationSettings(apiObject *appstream.ApplicationSettingsResponse) []interface{} {
Expand Down
Loading