Skip to content

Commit

Permalink
fix: update resource state even if a subtask fails on resource creati…
Browse files Browse the repository at this point in the history
…on (#289)
  • Loading branch information
ddebko authored Oct 18, 2022
1 parent 1882bef commit f95954c
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 46 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ Canonical reference for changes, improvements, and bugfixes for the Boundary Ter

### Bug Fixes

* Improve error message when authenticating to boundary.
* Improve error message when authenticating to boundary
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/290)).
* Set state before returning an error when creating a resource
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/289))

## 1.1.1 (October 12, 2022)

Expand Down
17 changes: 9 additions & 8 deletions internal/provider/resource_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func setFromGroupResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil
}

func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
md := meta.(*metaData)

var scopeId string
Expand Down Expand Up @@ -108,7 +108,12 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
if gcr == nil {
return diag.Errorf("group nil after create")
}
raw := gcr.GetResponse().Map
apiResponse := gcr.GetResponse().Map
defer func() {
if err := setFromGroupResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
}
}()

if val, ok := d.GetOk(groupMemberIdsKey); ok {
list := val.(*schema.Set).List()
Expand All @@ -118,16 +123,12 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
}
gcsmr, err := grps.SetMembers(ctx, gcr.Item.Id, gcr.Item.Version, memberIds)
if err != nil {
return diag.Errorf("error setting principals on role: %v", err)
return diag.Errorf("error setting members on group: %v", err)
}
if gcsmr == nil {
return diag.Errorf("group nil after setting members")
}
raw = gcsmr.GetResponse().Map
}

if err := setFromGroupResponseMap(d, raw); err != nil {
return diag.FromErr(err)
apiResponse = gcsmr.GetResponse().Map
}

return nil
Expand Down
15 changes: 8 additions & 7 deletions internal/provider/resource_host_set_static.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func setFromHostSetStaticResponseMap(d *schema.ResourceData, raw map[string]inte
return nil
}

func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
md := meta.(*metaData)

var hostsetHostCatalogId string
Expand Down Expand Up @@ -195,7 +195,12 @@ func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, me
if hscr == nil {
return diag.Errorf("nil host set after create")
}
raw := hscr.GetResponse().Map
apiResponse := hscr.GetResponse().Map
defer func() {
if err := setFromHostSetStaticResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
}
}()

if hostIds != nil {
hsshr, err := hsClient.SetHosts(ctx, hscr.Item.Id, hscr.Item.Version, hostIds)
Expand All @@ -205,11 +210,7 @@ func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, me
if hsshr == nil {
return diag.Errorf("nil host set after setting hosts")
}
raw = hsshr.GetResponse().Map
}

if err := setFromHostSetStaticResponseMap(d, raw); err != nil {
return diag.FromErr(err)
apiResponse = hsshr.GetResponse().Map
}

return nil
Expand Down
28 changes: 14 additions & 14 deletions internal/provider/resource_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil
}

func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
md := meta.(*metaData)

var scopeId string
Expand Down Expand Up @@ -151,38 +151,38 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
if tcr == nil {
return diag.Errorf("nil role after create")
}
raw := tcr.GetResponse().Map
apiResponse := tcr.GetResponse().Map
defer func() {
if err := setFromRoleResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
}
}()

var diags diag.Diagnostics
if principalIds != nil {
tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true))
switch {
case err != nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
case tspr == nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principal IDs"})
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principals"})
default:
raw = tspr.GetResponse().Map
apiResponse = tspr.GetResponse().Map
}
}

if grantStrings != nil {
tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true))
switch {
case err != nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
case tsgr == nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grant strings"})
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grants"})
default:
raw = tsgr.GetResponse().Map
apiResponse = tsgr.GetResponse().Map
}
}

if err := setFromRoleResponseMap(d, raw); err != nil {
return diag.FromErr(err)
}

return diags
return errs
}

func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand Down
24 changes: 15 additions & 9 deletions internal/provider/resource_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
return nil
}

func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
md := meta.(*metaData)

var scopeId string
Expand Down Expand Up @@ -256,23 +256,30 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
}

tc := targets.NewClient(md.client)

tcr, err := tc.Create(ctx, typeStr, scopeId, opts...)
if err != nil {
return diag.Errorf("error creating target: %v", err)
}
if tcr == nil {
return diag.Errorf("target nil after create")
}
raw := tcr.GetResponse().Map
apiResponse := tcr.GetResponse().Map
defer func() {
if err := setFromTargetResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
}
}()

version := tcr.Item.Version
if hostSourceIds != nil {
tur, err := tc.SetHostSources(ctx, tcr.Item.Id, version, hostSourceIds)
if err != nil {
return diag.Errorf("error setting host sources on target: %v", err)
}
raw = tur.GetResponse().Map
if tur == nil {
return diag.Errorf("nil target after setting host sources")
}
apiResponse = tur.GetResponse().Map
version = tur.Item.Version
}

Expand All @@ -288,11 +295,10 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
if err != nil {
return diag.Errorf("error setting credential sources on target: %v", err)
}
raw = tur.GetResponse().Map
}

if err := setFromTargetResponseMap(d, raw); err != nil {
return diag.FromErr(err)
if tur == nil {
return diag.Errorf("nil target after setting credential sources")
}
apiResponse = tur.GetResponse().Map
}

return nil
Expand Down
47 changes: 47 additions & 0 deletions internal/provider/resource_target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"regexp"
"testing"

"github.com/hashicorp/boundary/api"
Expand Down Expand Up @@ -130,6 +131,21 @@ resource "boundary_target" "foo" {
session_connection_limit = 7
worker_filter = "type == \"bar\""
}`, fooTargetDescriptionUpdate)

fooTargetPartialSuccess = fmt.Sprintf(`
resource "boundary_target" "foo" {
name = "expected_to_fail"
description = "%s"
type = "tcp"
scope_id = boundary_scope.proj1.id
default_port = 80
depends_on = [boundary_role.proj1_admin]
session_max_seconds = 7000
session_connection_limit = 7
injected_application_credential_source_ids = [
boundary_credential_library_vault.bar.id
]
}`, fooTargetDescription)
)

func TestAccTarget(t *testing.T) {
Expand Down Expand Up @@ -200,6 +216,37 @@ func TestAccTarget(t *testing.T) {
),
},
importStep("boundary_target.foo"),
{
// test updating state file when the target is created, but fails on associating an invalid injected credential source to a tcp target type
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, fooBarCredLibs, fooTargetPartialSuccess),
Check: resource.ComposeTestCheckFunc(
testAccCheckTargetResourceExists(provider, "boundary_target.foo"),
resource.TestCheckResourceAttr("boundary_target.foo", DescriptionKey, ""),
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "80"),
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "7000"),
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "7"),
resource.TestCheckResourceAttr("boundary_target.foo", targetHostSourceIdsKey+".%", "0"),
resource.TestCheckResourceAttr("boundary_target.foo", targetInjectedAppCredentialSourceIdsKey+".%", "0"),
),
ExpectError: regexp.MustCompile("Unable to set credential sources in target: tcp.VetCredentialSources: tcp.Target only supports credential purpose"),
},
importStep("boundary_target.foo", targetInjectedAppCredentialSourceIdsKey),
{
// test resolving invalid injected credential source error without raising duplicate name error, due to state file not being in sync.
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, fooBarCredLibs, fooTargetUpdateUnsetHostAndCredSources),
Check: resource.ComposeTestCheckFunc(
testAccCheckTargetResourceExists(provider, "boundary_target.foo"),
resource.TestCheckResourceAttr("boundary_target.foo", DescriptionKey, fooTargetDescriptionUpdate),
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "80"),
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "7000"),
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "7"),
resource.TestCheckResourceAttr("boundary_target.foo", targetWorkerFilterKey, `type == "bar"`),
resource.TestCheckResourceAttr("boundary_target.foo", targetHostSourceIdsKey+".%", "0"),
resource.TestCheckResourceAttr("boundary_target.foo", targetInjectedAppCredentialSourceIdsKey+".%", "0"),
resource.TestCheckResourceAttr("boundary_target.foo", targetBrokeredCredentialSourceIdsKey+".%", "0"),
),
},
importStep("boundary_target.foo"),
},
})
}
Expand Down
15 changes: 8 additions & 7 deletions internal/provider/resource_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func setFromUserResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil
}

func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
md := meta.(*metaData)

var scopeId string
Expand Down Expand Up @@ -106,7 +106,12 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
if ucr == nil {
return diag.Errorf("user nil after create")
}
raw := ucr.GetResponse().Map
apiResponse := ucr.GetResponse().Map
defer func() {
if err := setFromUserResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
}
}()

if val, ok := d.GetOk(userAccountIDsKey); ok {
list := val.(*schema.Set).List()
Expand All @@ -121,11 +126,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
if usrac == nil {
return diag.Errorf("user nil after setting accounts")
}
raw = usrac.GetResponse().Map
}

if err := setFromUserResponseMap(d, raw); err != nil {
return diag.FromErr(err)
apiResponse = usrac.GetResponse().Map
}

return nil
Expand Down

0 comments on commit f95954c

Please sign in to comment.