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

add namespaces data source #2212

Merged
merged 10 commits into from Mar 27, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Expand Up @@ -2,10 +2,11 @@

FEATURES:
* Add `granularity` to Secrets Sync destination resources. Requires Vault 1.16+. ([#2202](https://github.com/hashicorp/terraform-provider-vault/pull/2202))

IMPROVEMENTS:
* Add support for `allowed_kubernetes_namespace_selector` in `vault_kubernetes_secret_backend_role` ([#2180](https://github.com/hashicorp/terraform-provider-vault/pull/2180)).
* Add new data source `vault_namespace`. Requires Vault Enterprise: ([#2208](https://github.com/hashicorp/terraform-provider-vault/pull/2208)).
* Add new data source `vault_namespaces`. Requires Vault Enterprise: ([#2212](https://github.com/hashicorp/terraform-provider-vault/pull/2212)).

IMPROVEMENTS:
* Enable Secrets Sync Association resource to track sync status across all subkeys of a secret ([#2202](https://github.com/hashicorp/terraform-provider-vault/pull/2202))

BUGS:
Expand Down
68 changes: 68 additions & 0 deletions vault/data_source_namespaces.go
@@ -0,0 +1,68 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package vault

import (
"context"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"

"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/terraform-provider-vault/util/mountutil"
)

func namespacesDataSource() *schema.Resource {
return &schema.Resource{
ReadContext: provider.ReadContextWrapper(namespacesDataSourceRead),

Schema: map[string]*schema.Schema{
consts.FieldPaths: {
Type: schema.TypeSet,
Computed: true,
Description: "Namespace paths.",
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func namespacesDataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, e := provider.GetClient(d, meta)
if e != nil {
return diag.FromErr(e)
}

log.Printf("[DEBUG] Reading namespaces from Vault")

resp, err := client.Logical().ListWithContext(ctx, consts.SysNamespaceRoot)
if err != nil {
return diag.Errorf("error reading namespaces from Vault: %s", err)
}
if err := d.Set(consts.FieldPaths, flattenPaths(resp)); err != nil {
return diag.Errorf("error setting %q to state: %s", consts.FieldPaths, err)
}

id := mountutil.NormalizeMountPath(client.Namespace())
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
d.SetId(id)

return nil
}

func flattenPaths(resp *api.Secret) []string {
if resp == nil {
return nil
}

var paths []string
if keys, ok := resp.Data["keys"]; ok {
for _, key := range keys.([]interface{}) {
paths = append(paths, mountutil.TrimSlashes(key.(string)))
}
}
return paths
}
73 changes: 73 additions & 0 deletions vault/data_source_namespaces_test.go
@@ -0,0 +1,73 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/testutil"
)

func TestAccDataSourceNamespaces(t *testing.T) {
testutil.SkipTestAccEnt(t)

ns := acctest.RandomWithPrefix("tf-ns")
resourceName := "data.vault_namespaces"

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testAccDataSourceNamespacesConfig(ns, 3),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName+".test", consts.FieldPaths+".#", "3"),
resource.TestCheckTypeSetElemAttr(resourceName+".test", consts.FieldPaths+".*", "test-0"),
resource.TestCheckTypeSetElemAttr(resourceName+".test", consts.FieldPaths+".*", "test-1"),
resource.TestCheckTypeSetElemAttr(resourceName+".test", consts.FieldPaths+".*", "test-2"),
resource.TestCheckResourceAttr(resourceName+".test", consts.FieldNamespace, ns),
// test nested which will not have any namespaces under it
resource.TestCheckResourceAttr(resourceName+".nested", consts.FieldPaths+".#", "0"),
resource.TestCheckResourceAttr(resourceName+".nested", consts.FieldNamespace, ns+"/test-0/nested"),
),
},
},
})
}

func testAccDataSourceNamespacesConfig(ns string, count int) string {
config := fmt.Sprintf(`
resource "vault_namespace" "parent" {
path = %q
}

resource "vault_namespace" "test" {
count = %d
namespace = vault_namespace.parent.path
path = "test-${count.index}"
}

# this will create a namespace with the path "test/test-0/nested"
resource "vault_namespace" "nested" {
namespace = vault_namespace.test[0].path_fq
path = "nested"
}

data "vault_namespaces" "test" {
namespace = vault_namespace.parent.path
depends_on = [vault_namespace.test]
}

data "vault_namespaces" "nested" {
namespace = vault_namespace.nested.path_fq
}
`, ns, count)

return config
}
5 changes: 5 additions & 0 deletions vault/provider.go
Expand Up @@ -78,6 +78,11 @@ var (
Resource: UpdateSchemaResource(adAccessCredentialsDataSource()),
PathInventory: []string{"/ad/creds/{role}"},
},
"vault_namespaces": {
Resource: UpdateSchemaResource(namespacesDataSource()),
PathInventory: []string{"/sys/namespaces"},
EnterpriseOnly: true,
},
"vault_nomad_access_token": {
Resource: UpdateSchemaResource(nomadAccessCredentialsDataSource()),
PathInventory: []string{"/nomad/creds/{role}"},
Expand Down
51 changes: 51 additions & 0 deletions website/docs/d/namespaces.html.md
@@ -0,0 +1,51 @@
---
layout: "vault"
page_title: "Vault: vault_namespaces data source"
sidebar_current: "docs-vault-datasource-namespaces"
description: |-
Fetches a list of all direct child namespaces in Vault
---

# vault\_namespace

Lists all direct child [Namespaces](https://developer.hashicorp.com/vault/docs/enterprise/namespaces) in Vault.

**Note** this feature is available only with Vault Enterprise.

## Example Usage

### Child namespaces

```hcl
data "vault_namespaces" "children" {}
```

### Nested namespace

To fetch the details of nested namespaces:

```hcl
data "vault_namespaces" "children" {
namespace = "parent"
}

data "vault_namespace" "child" {
for_each = data.vault_namespaces.children.paths
namespace = data.vault_namespaces.children.namespace
path = each.key
}
```

## Argument Reference

The following arguments are supported:

* `namespace` - (Optional) The namespace to provision the resource in.
The value should not contain leading or trailing forward slashes.
The `namespace` is always relative to the provider's configured [namespace](/docs/providers/vault#namespace).

## Attributes Reference

In addition to the above arguments, the following attributes are exported:

* `paths` - Set of the paths of direct child namespaces.
4 changes: 4 additions & 0 deletions website/vault.erb
Expand Up @@ -149,6 +149,10 @@
<a href="/docs/providers/vault/d/namespace.html">vault_namespace</a>
</li>

<li<%= sidebar_current("docs-vault-datasource-namespaces") %>>
<a href="/docs/providers/vault/d/namespaces.html">vault_namespaces</a>
</li>

</ul>
</li>

Expand Down