Compare commits

...
3 Commits
Author SHA1 Message Date
Damian Debkowski f95954c83d fix: update resource state even if a subtask fails on resource creation (#289)
Release / go-version (push) Successful in 9s
Release / release-notes (push) Successful in 32s
Release / Terraform Provider Release (push) Failing after 0s
2022-10-17 22:00:23 -07:00
Damian Debkowski 1882beff3c fix: improve error message for invalid provider credentials (#290) 2022-10-17 11:13:45 -07:00
Damian Debkowski 807db1bef1 Support Vault Credential Library Mapping Overrides (#287) 2022-10-13 09:53:42 -07:00
12 changed files with 387 additions and 68 deletions

No files matched your search

+15
View File
@@ -2,6 +2,21 @@
Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider. Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider.
## Next
### New and Improved
* Add support for setting mapping overrides for vault credential libraries
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/287)).
### Bug Fixes
* 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) ## 1.1.1 (October 12, 2022)
### Bug Fixes ### Bug Fixes
@@ -56,6 +56,33 @@ resource "boundary_credential_library_vault" "bar" {
} }
EOT EOT
} }
resource "boundary_credential_library_vault" "baz" {
name = "baz"
description = "vault username password credential with mapping overrides"
credential_store_id = boundary_credential_store_vault.foo.id
path = "my/secret/baz" # change to Vault backend path
http_method = "GET"
credential_type = "username_password"
credential_mapping_overrides = {
password_attribute = "alternative_password_label"
username_attribute = "alternative_username_label"
}
}
resource "boundary_credential_library_vault" "quz" {
name = "quz"
description = "vault ssh private key credential with mapping overrides"
credential_store_id = boundary_credential_store_vault.foo.id
path = "my/secret/quz" # change to Vault backend path
http_method = "GET"
credential_type = "ssh_private_key"
credential_mapping_overrides = {
private_key_attribute = "alternative_key_label"
private_key_passphrase_attribute = "alternative_passphrase_label"
username_attribute = "alternative_username_label"
}
}
``` ```
<!-- schema generated by tfplugindocs --> <!-- schema generated by tfplugindocs -->
@@ -68,6 +95,7 @@ EOT
### Optional ### Optional
- `credential_mapping_overrides` (Map of String) The credential mapping override.
- `credential_type` (String) The type of credential the library generates. - `credential_type` (String) The type of credential the library generates.
- `description` (String) The Vault credential library description. - `description` (String) The Vault credential library description.
- `http_method` (String) The HTTP method the library uses when requesting credentials from Vault. Defaults to 'GET' - `http_method` (String) The HTTP method the library uses when requesting credentials from Vault. Defaults to 'GET'
@@ -41,3 +41,30 @@ resource "boundary_credential_library_vault" "bar" {
} }
EOT EOT
} }
resource "boundary_credential_library_vault" "baz" {
name = "baz"
description = "vault username password credential with mapping overrides"
credential_store_id = boundary_credential_store_vault.foo.id
path = "my/secret/baz" # change to Vault backend path
http_method = "GET"
credential_type = "username_password"
credential_mapping_overrides = {
password_attribute = "alternative_password_label"
username_attribute = "alternative_username_label"
}
}
resource "boundary_credential_library_vault" "quz" {
name = "quz"
description = "vault ssh private key credential with mapping overrides"
credential_store_id = boundary_credential_store_vault.foo.id
path = "my/secret/quz" # change to Vault backend path
http_method = "GET"
credential_type = "ssh_private_key"
credential_mapping_overrides = {
private_key_attribute = "alternative_key_label"
private_key_passphrase_attribute = "alternative_passphrase_label"
username_attribute = "alternative_username_label"
}
}
+10
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net/http"
"strings" "strings"
"github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api"
@@ -176,6 +177,15 @@ func providerAuthenticate(ctx context.Context, d *schema.ResourceData, md *metaD
at, err := am.Authenticate(ctx, authMethodId.(string), "login", credentials) at, err := am.Authenticate(ctx, authMethodId.(string), "login", credentials)
if err != nil { if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
statusCode := apiErr.Response().StatusCode()
if statusCode == http.StatusNotFound {
return fmt.Errorf("unknown auth_method_id: %s", err.Error())
}
if statusCode == http.StatusUnauthorized {
return fmt.Errorf("invalid login name or password: %s", err.Error())
}
}
return err return err
} }
md.client.SetToken(at.Attributes["token"].(string)) md.client.SetToken(at.Attributes["token"].(string))
@@ -11,11 +11,12 @@ import (
) )
const ( const (
credentialStoreIdKey = "credential_store_id" credentialStoreIdKey = "credential_store_id"
credentialLibraryVaultHttpMethodKey = "http_method" credentialLibraryVaultHttpMethodKey = "http_method"
credentialLibraryVaultHttpRequestBodyKey = "http_request_body" credentialLibraryVaultHttpRequestBodyKey = "http_request_body"
credentialLibraryVaultPathKey = "path" credentialLibraryVaultPathKey = "path"
credentialLibraryCredentialTypeKey = "credential_type" credentialLibraryCredentialTypeKey = "credential_type"
credentialLibraryCredentialMappingOverridesKey = "credential_mapping_overrides"
) )
var libraryVaultAttrs = []string{ var libraryVaultAttrs = []string{
@@ -78,6 +79,11 @@ func resourceCredentialLibraryVault() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
credentialLibraryCredentialMappingOverridesKey: {
Description: "The credential mapping override.",
Type: schema.TypeMap,
Optional: true,
},
}, },
} }
} }
@@ -93,6 +99,10 @@ func setFromVaultCredentialLibraryResponseMap(d *schema.ResourceData, raw map[st
return err return err
} }
if err := d.Set(credentialLibraryCredentialMappingOverridesKey, raw[credentialLibraryCredentialMappingOverridesKey]); err != nil {
return err
}
if attrsVal, ok := raw["attributes"]; ok { if attrsVal, ok := raw["attributes"]; ok {
attrs := attrsVal.(map[string]interface{}) attrs := attrsVal.(map[string]interface{})
for _, v := range libraryVaultAttrs { for _, v := range libraryVaultAttrs {
@@ -129,6 +139,10 @@ func resourceCredentialLibraryCreateVault(ctx context.Context, d *schema.Resourc
if v, ok := d.GetOk(credentialLibraryCredentialTypeKey); ok { if v, ok := d.GetOk(credentialLibraryCredentialTypeKey); ok {
opts = append(opts, credentiallibraries.WithCredentialType(v.(string))) opts = append(opts, credentiallibraries.WithCredentialType(v.(string)))
} }
if v, ok := d.GetOk(credentialLibraryCredentialMappingOverridesKey); ok {
mappingOverrides := v.(map[string]interface{})
opts = append(opts, credentiallibraries.WithCredentialMappingOverrides(mappingOverrides))
}
var credentialStoreId string var credentialStoreId string
cid, ok := d.GetOk(credentialStoreIdKey) cid, ok := d.GetOk(credentialStoreIdKey)
@@ -216,6 +230,40 @@ func resourceCredentialLibraryUpdateVault(ctx context.Context, d *schema.Resourc
opts = append(opts, credentiallibraries.WithVaultCredentialLibraryPath(v.(string))) opts = append(opts, credentiallibraries.WithVaultCredentialLibraryPath(v.(string)))
} }
} }
if d.HasChange(credentialLibraryCredentialMappingOverridesKey) {
var oldMapping, newMapping map[string]interface{}
old, new := d.GetChange(credentialLibraryCredentialMappingOverridesKey)
if old == nil {
old = map[string]interface{}{}
}
oldMapping = old.(map[string]interface{})
if new == nil {
new = map[string]interface{}{}
}
newMapping = new.(map[string]interface{})
newAttrs := []string{}
for k := range newMapping {
newAttrs = append(newAttrs, k)
}
for oldAttr := range oldMapping {
isRemoved := true
for _, newAttr := range newAttrs {
if oldAttr == newAttr {
isRemoved = false
break
}
}
if isRemoved {
newMapping[oldAttr] = nil
}
}
opts = append(opts, credentiallibraries.WithCredentialMappingOverrides(newMapping))
}
if len(opts) > 0 { if len(opts) > 0 {
opts = append(opts, credentiallibraries.WithAutomaticVersioning(true)) opts = append(opts, credentiallibraries.WithAutomaticVersioning(true))
@@ -16,24 +16,26 @@ import (
) )
const ( const (
vaultCredResc = "boundary_credential_library_vault.example" vaultCredResc = "boundary_credential_library_vault.example"
vaultCredTypedResc = "boundary_credential_library_vault.typed_example" vaultCredTypedResc = "boundary_credential_library_vault.typed_example"
vaultCredLibName = "foo" vaultCredUsernamePasswordResc = "boundary_credential_library_vault.username_password_mapping_override"
vaultCredLibDesc = "the foo" vaultCredSshPrivateKeyResc = "boundary_credential_library_vault.ssh_private_key_mapping_override"
vaultCredLibPath = "/foo/bar" vaultCredLibName = "foo"
vaultCredLibMethodGet = "GET" vaultCredLibDesc = "the foo"
vaultCredLibMethodPost = "POST" vaultCredLibPath = "/foo/bar"
vaultCredLibRequestBody = "foobar" vaultCredLibMethodGet = "GET"
vaultCredLibStringUpdate = "_random" vaultCredLibMethodPost = "POST"
vaultCredLibRequestBody = "foobar"
vaultCredLibStringUpdate = "_random"
) )
var vaultCredLibResource = fmt.Sprintf(` var vaultCredLibResource = fmt.Sprintf(`
resource "boundary_credential_library_vault" "example" { resource "boundary_credential_library_vault" "example" {
name = "%s" name = "%s"
description = "%s" description = "%s"
credential_store_id = boundary_credential_store_vault.example.id credential_store_id = boundary_credential_store_vault.example.id
path = "%s" path = "%s"
http_method = "%s" http_method = "%s"
}`, vaultCredLibName, }`, vaultCredLibName,
vaultCredLibDesc, vaultCredLibDesc,
vaultCredLibPath, vaultCredLibPath,
@@ -41,12 +43,12 @@ resource "boundary_credential_library_vault" "example" {
var vaultCredLibResourceUpdate = fmt.Sprintf(` var vaultCredLibResourceUpdate = fmt.Sprintf(`
resource "boundary_credential_library_vault" "example" { resource "boundary_credential_library_vault" "example" {
name = "%s" name = "%s"
description = "%s" description = "%s"
credential_store_id = boundary_credential_store_vault.example.id credential_store_id = boundary_credential_store_vault.example.id
path = "%s" path = "%s"
http_method = "%s" http_method = "%s"
http_request_body = "%s" http_request_body = "%s"
}`, vaultCredLibName+vaultCredLibStringUpdate, }`, vaultCredLibName+vaultCredLibStringUpdate,
vaultCredLibDesc+vaultCredLibStringUpdate, vaultCredLibDesc+vaultCredLibStringUpdate,
vaultCredLibPath+vaultCredLibStringUpdate, vaultCredLibPath+vaultCredLibStringUpdate,
@@ -66,6 +68,71 @@ resource "boundary_credential_library_vault" "typed_example" {
vaultCredLibPath, vaultCredLibPath,
vaultCredLibMethodGet) vaultCredLibMethodGet)
var vaultUsernamePasswordMappingOverrideCredLibResource = fmt.Sprintf(`
resource "boundary_credential_library_vault" "username_password_mapping_override" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
http_method = "%s"
credential_type = "username_password"
credential_mapping_overrides = {
password_attribute = "alternative_password_label"
username_attribute = "alternative_username_label"
}
}`, vaultCredLibName,
vaultCredLibDesc,
vaultCredLibPath,
vaultCredLibMethodGet)
var vaultUsernamePasswordMappingOverrideCredLibResourceUpdate = fmt.Sprintf(`
resource "boundary_credential_library_vault" "username_password_mapping_override" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
http_method = "%s"
credential_type = "username_password"
credential_mapping_overrides = {
password_attribute = "updated_password_label"
username_attribute = "updated_username_label"
}
}`, vaultCredLibName,
vaultCredLibDesc,
vaultCredLibPath,
vaultCredLibMethodGet)
var vaultUsernamePasswordMappingOverrideCredLibResourceRemove = fmt.Sprintf(`
resource "boundary_credential_library_vault" "username_password_mapping_override" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
http_method = "%s"
credential_type = "username_password"
}`, vaultCredLibName,
vaultCredLibDesc,
vaultCredLibPath,
vaultCredLibMethodGet)
var vaultSshPrivateKeyMappingOverrideCredLibResource = fmt.Sprintf(`
resource "boundary_credential_library_vault" "ssh_private_key_mapping_override" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
http_method = "%s"
credential_type = "ssh_private_key"
credential_mapping_overrides = {
private_key_attribute = "alternative_key_label"
private_key_passphrase_attribute = "alternative_passphrase_label"
username_attribute = "alternative_username_label"
}
}`, vaultCredLibName,
vaultCredLibDesc,
vaultCredLibPath,
vaultCredLibMethodGet)
func TestAccCredentialLibraryVault(t *testing.T) { func TestAccCredentialLibraryVault(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...) tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown() defer tc.Shutdown()
@@ -132,6 +199,74 @@ func TestAccCredentialLibraryVault(t *testing.T) {
), ),
}, },
importStep(vaultCredResc), importStep(vaultCredResc),
{
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultCredLibResourceUpdate, vaultUsernamePasswordMappingOverrideCredLibResource),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, NameKey, vaultCredLibName),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, DescriptionKey, vaultCredLibDesc),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultPathKey, vaultCredLibPath),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpMethodKey, vaultCredLibMethodGet),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpRequestBodyKey, ""),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryCredentialTypeKey, "username_password"),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, "credential_mapping_overrides.password_attribute", "alternative_password_label"),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, "credential_mapping_overrides.username_attribute", "alternative_username_label"),
testAccCheckCredentialLibraryVaultResourceExists(provider, vaultCredUsernamePasswordResc),
),
},
importStep(vaultCredResc),
{
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultCredLibResourceUpdate, vaultUsernamePasswordMappingOverrideCredLibResourceUpdate),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, NameKey, vaultCredLibName),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, DescriptionKey, vaultCredLibDesc),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultPathKey, vaultCredLibPath),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpMethodKey, vaultCredLibMethodGet),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpRequestBodyKey, ""),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryCredentialTypeKey, "username_password"),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, "credential_mapping_overrides.password_attribute", "updated_password_label"),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, "credential_mapping_overrides.username_attribute", "updated_username_label"),
testAccCheckCredentialLibraryVaultResourceExists(provider, vaultCredUsernamePasswordResc),
),
},
importStep(vaultCredResc),
{
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultCredLibResourceUpdate, vaultUsernamePasswordMappingOverrideCredLibResourceRemove),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, NameKey, vaultCredLibName),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, DescriptionKey, vaultCredLibDesc),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultPathKey, vaultCredLibPath),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpMethodKey, vaultCredLibMethodGet),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryVaultHttpRequestBodyKey, ""),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryCredentialTypeKey, "username_password"),
resource.TestCheckResourceAttr(vaultCredUsernamePasswordResc, credentialLibraryCredentialMappingOverridesKey+".%", "0"),
testAccCheckCredentialLibraryVaultResourceExists(provider, vaultCredUsernamePasswordResc),
),
},
importStep(vaultCredResc),
{
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultCredLibResourceUpdate, vaultSshPrivateKeyMappingOverrideCredLibResource),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, NameKey, vaultCredLibName),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, DescriptionKey, vaultCredLibDesc),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, credentialLibraryVaultPathKey, vaultCredLibPath),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, credentialLibraryVaultHttpMethodKey, vaultCredLibMethodGet),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, credentialLibraryVaultHttpRequestBodyKey, ""),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, credentialLibraryCredentialTypeKey, "ssh_private_key"),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, "credential_mapping_overrides.private_key_attribute", "alternative_key_label"),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, "credential_mapping_overrides.private_key_passphrase_attribute", "alternative_passphrase_label"),
resource.TestCheckResourceAttr(vaultCredSshPrivateKeyResc, "credential_mapping_overrides.username_attribute", "alternative_username_label"),
testAccCheckCredentialLibraryVaultResourceExists(provider, vaultCredSshPrivateKeyResc),
),
},
importStep(vaultCredResc),
}, },
}) })
} }
+9 -8
View File
@@ -75,7 +75,7 @@ func setFromGroupResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil 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) md := meta.(*metaData)
var scopeId string var scopeId string
@@ -108,7 +108,12 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
if gcr == nil { if gcr == nil {
return diag.Errorf("group nil after create") 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 { if val, ok := d.GetOk(groupMemberIdsKey); ok {
list := val.(*schema.Set).List() list := val.(*schema.Set).List()
@@ -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) gcsmr, err := grps.SetMembers(ctx, gcr.Item.Id, gcr.Item.Version, memberIds)
if err != nil { 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 { if gcsmr == nil {
return diag.Errorf("group nil after setting members") return diag.Errorf("group nil after setting members")
} }
raw = gcsmr.GetResponse().Map apiResponse = gcsmr.GetResponse().Map
}
if err := setFromGroupResponseMap(d, raw); err != nil {
return diag.FromErr(err)
} }
return nil return nil
@@ -139,7 +139,7 @@ func setFromHostSetStaticResponseMap(d *schema.ResourceData, raw map[string]inte
return nil 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) md := meta.(*metaData)
var hostsetHostCatalogId string var hostsetHostCatalogId string
@@ -195,7 +195,12 @@ func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, me
if hscr == nil { if hscr == nil {
return diag.Errorf("nil host set after create") 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 { if hostIds != nil {
hsshr, err := hsClient.SetHosts(ctx, hscr.Item.Id, hscr.Item.Version, hostIds) hsshr, err := hsClient.SetHosts(ctx, hscr.Item.Id, hscr.Item.Version, hostIds)
@@ -205,11 +210,7 @@ func resourceHostSetStaticCreate(ctx context.Context, d *schema.ResourceData, me
if hsshr == nil { if hsshr == nil {
return diag.Errorf("nil host set after setting hosts") return diag.Errorf("nil host set after setting hosts")
} }
raw = hsshr.GetResponse().Map apiResponse = hsshr.GetResponse().Map
}
if err := setFromHostSetStaticResponseMap(d, raw); err != nil {
return diag.FromErr(err)
} }
return nil return nil
+14 -14
View File
@@ -94,7 +94,7 @@ func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil 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) md := meta.(*metaData)
var scopeId string var scopeId string
@@ -151,18 +151,22 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
if tcr == nil { if tcr == nil {
return diag.Errorf("nil role after create") 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 { if principalIds != nil {
tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true)) tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true))
switch { switch {
case err != nil: 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: 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: default:
raw = tspr.GetResponse().Map apiResponse = tspr.GetResponse().Map
} }
} }
@@ -170,19 +174,15 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true)) tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true))
switch { switch {
case err != nil: 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: 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: default:
raw = tsgr.GetResponse().Map apiResponse = tsgr.GetResponse().Map
} }
} }
if err := setFromRoleResponseMap(d, raw); err != nil { return errs
return diag.FromErr(err)
}
return diags
} }
func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+15 -9
View File
@@ -155,7 +155,7 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
return nil 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) md := meta.(*metaData)
var scopeId string var scopeId string
@@ -256,7 +256,6 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
} }
tc := targets.NewClient(md.client) tc := targets.NewClient(md.client)
tcr, err := tc.Create(ctx, typeStr, scopeId, opts...) tcr, err := tc.Create(ctx, typeStr, scopeId, opts...)
if err != nil { if err != nil {
return diag.Errorf("error creating target: %v", err) return diag.Errorf("error creating target: %v", err)
@@ -264,7 +263,12 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
if tcr == nil { if tcr == nil {
return diag.Errorf("target nil after create") 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 version := tcr.Item.Version
if hostSourceIds != nil { if hostSourceIds != nil {
@@ -272,7 +276,10 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
if err != nil { if err != nil {
return diag.Errorf("error setting host sources on target: %v", err) 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 version = tur.Item.Version
} }
@@ -288,11 +295,10 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
if err != nil { if err != nil {
return diag.Errorf("error setting credential sources on target: %v", err) return diag.Errorf("error setting credential sources on target: %v", err)
} }
raw = tur.GetResponse().Map if tur == nil {
} return diag.Errorf("nil target after setting credential sources")
}
if err := setFromTargetResponseMap(d, raw); err != nil { apiResponse = tur.GetResponse().Map
return diag.FromErr(err)
} }
return nil return nil
+47
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"regexp"
"testing" "testing"
"github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api"
@@ -130,6 +131,21 @@ resource "boundary_target" "foo" {
session_connection_limit = 7 session_connection_limit = 7
worker_filter = "type == \"bar\"" worker_filter = "type == \"bar\""
}`, fooTargetDescriptionUpdate) }`, 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) { func TestAccTarget(t *testing.T) {
@@ -200,6 +216,37 @@ func TestAccTarget(t *testing.T) {
), ),
}, },
importStep("boundary_target.foo"), 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"),
}, },
}) })
} }
+8 -7
View File
@@ -73,7 +73,7 @@ func setFromUserResponseMap(d *schema.ResourceData, raw map[string]interface{})
return nil 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) md := meta.(*metaData)
var scopeId string var scopeId string
@@ -106,7 +106,12 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
if ucr == nil { if ucr == nil {
return diag.Errorf("user nil after create") 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 { if val, ok := d.GetOk(userAccountIDsKey); ok {
list := val.(*schema.Set).List() list := val.(*schema.Set).List()
@@ -121,11 +126,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
if usrac == nil { if usrac == nil {
return diag.Errorf("user nil after setting accounts") return diag.Errorf("user nil after setting accounts")
} }
raw = usrac.GetResponse().Map apiResponse = usrac.GetResponse().Map
}
if err := setFromUserResponseMap(d, raw); err != nil {
return diag.FromErr(err)
} }
return nil return nil