diff --git a/vault/resource_mount.go b/vault/resource_mount.go index 82a1050eb..70991b080 100644 --- a/vault/resource_mount.go +++ b/vault/resource_mount.go @@ -66,6 +66,15 @@ func mountResource() *schema.Resource { Description: "Accessor of the mount", }, + "local": { + Type: schema.TypeBool, + Required: false, + Optional: true, + Computed: false, + ForceNew: true, + Description: "Local mount flag that can be explicitly set to true to enforce local mount in HA environment", + }, + "options": { Type: schema.TypeMap, Required: false, @@ -88,6 +97,7 @@ func mountWrite(d *schema.ResourceData, meta interface{}) error { DefaultLeaseTTL: fmt.Sprintf("%ds", d.Get("default_lease_ttl_seconds")), MaxLeaseTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds")), }, + Local: d.Get("local").(bool), Options: opts(d), } @@ -180,6 +190,7 @@ func mountRead(d *schema.ResourceData, meta interface{}) error { d.Set("default_lease_ttl_seconds", mount.Config.DefaultLeaseTTL) d.Set("max_lease_ttl_seconds", mount.Config.MaxLeaseTTL) d.Set("accessor", mount.Accessor) + d.Set("local", mount.Local) d.Set("options", mount.Options) return nil diff --git a/vault/resource_mount_test.go b/vault/resource_mount_test.go index bcc9262ba..7e2df25f1 100644 --- a/vault/resource_mount_test.go +++ b/vault/resource_mount_test.go @@ -55,6 +55,26 @@ func TestResourceMount(t *testing.T) { }) } +// Test Local flag + +func TestResourceMount_Local(t *testing.T) { + path := "example-" + acctest.RandString(10) + resource.Test(t, resource.TestCase{ + Providers: testProviders, + PreCheck: func() { testAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testResourceMount_InitialConfigLocalMount(path), + Check: testResourceMount_InitialCheckLocalMount(path), + }, + { + Config: testResourceMount_UpdateConfigLocalMount, + Check: testResourceMount_UpdateCheckLocalMount, + }, + }, + }) +} + func testResourceMount_initialConfig(path string) string { return fmt.Sprintf(` resource "vault_mount" "test" { @@ -174,6 +194,99 @@ func testResourceMount_updateCheck(s *terraform.State) error { return nil } +func testResourceMount_InitialConfigLocalMount(path string) string { + return fmt.Sprintf(` +resource "vault_mount" "test" { + path = "%s" + type = "kv" + description = "Example local mount for testing" + default_lease_ttl_seconds = 3600 + max_lease_ttl_seconds = 36000 + local = true + options = { + version = "1" + } +} +`, path) +} + +func testResourceMount_InitialCheckLocalMount(expectedPath string) resource.TestCheckFunc { + return func(s *terraform.State) error { + resourceState := s.Modules[0].Resources["vault_mount.test"] + if resourceState == nil { + return fmt.Errorf("resource not found in state") + } + + instanceState := resourceState.Primary + if instanceState == nil { + return fmt.Errorf("resource has no primary instance") + } + + path := instanceState.ID + + if path != instanceState.Attributes["path"] { + return fmt.Errorf("id %q doesn't match path %q", path, instanceState.Attributes["path"]) + } + + if path != expectedPath { + return fmt.Errorf("unexpected path %q, expected %q", path, expectedPath) + } + + mount, err := findMount(path) + if err != nil { + return fmt.Errorf("error reading back mount %q: %s", path, err) + } + + if wanted := true; mount.Local != wanted { + return fmt.Errorf("local is %v; wanted %t", mount.Description, wanted) + } + + return nil + } +} + +var testResourceMount_UpdateConfigLocalMount = ` + +resource "vault_mount" "test" { + path = "remountingExample" + type = "kv" + description = "Example mount for testing" + default_lease_ttl_seconds = 7200 + max_lease_ttl_seconds = 72000 + local = false + options = { + version = "1" + } +} + +` + +func testResourceMount_UpdateCheckLocalMount(s *terraform.State) error { + resourceState := s.Modules[0].Resources["vault_mount.test"] + instanceState := resourceState.Primary + + path := instanceState.ID + + if path != instanceState.Attributes["path"] { + return fmt.Errorf("id doesn't match path") + } + + if path != "remountingExample" { + return fmt.Errorf("unexpected path value") + } + + mount, err := findMount(path) + if err != nil { + return fmt.Errorf("error reading back mount: %s", err) + } + + if wanted := false; mount.Local != wanted { + return fmt.Errorf("local is %v; wanted %t", mount.Description, wanted) + } + + return nil +} + func findMount(path string) (*api.MountOutput, error) { client := testProvider.Meta().(*api.Client) diff --git a/website/docs/r/mount.html.md b/website/docs/r/mount.html.md index 345d4ba73..9d0cf4fa0 100644 --- a/website/docs/r/mount.html.md +++ b/website/docs/r/mount.html.md @@ -33,6 +33,8 @@ The following arguments are supported: * `max_lease_ttl_seconds` - (Optional) Maximum possible lease duration for tokens and secrets in seconds +* `local` - (Optional) Boolean flag that can be explicitly set to true to enforce local mount in HA environment + * `options` - (Optional) Specifies mount type specific options that are passed to the backend ## Attributes Reference