feat: Add boundary_role data source (#743)
This commit is contained in:
1 parent
08f651b123
commit
e9f7b89ad2
5 files changed
+366
No files matched your search
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||||
|
page_title: "boundary_role Data Source - terraform-provider-boundary"
|
||||||
|
subcategory: ""
|
||||||
|
description: |-
|
||||||
|
The boundary_role data source allows you to find a Boundary role.
|
||||||
|
---
|
||||||
|
|
||||||
|
# boundary_role (Data Source)
|
||||||
|
|
||||||
|
The boundary_role data source allows you to find a Boundary role.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
# Role from the global scope
|
||||||
|
data "boundary_role" "global_role" {
|
||||||
|
name = "global_role_one"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Role from an org scope
|
||||||
|
data "boundary_scope" "org" {
|
||||||
|
name = "org_one"
|
||||||
|
scope_id = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "boundary_role" "org_role" {
|
||||||
|
name = "org_role_one"
|
||||||
|
scope_id = data.boundary_scope.org.id
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `name` (String) The name of the role to retrieve.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
- `scope_id` (String) The scope ID in which the resource is created. Defaults `global` if unset.
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `description` (String) The description of the retrieved role.
|
||||||
|
- `grant_scope_ids` (Set of String) The list of scope IDs for the role's grants.
|
||||||
|
- `grant_strings` (Set of String) The list of stringified grants for the role.
|
||||||
|
- `id` (String) The ID of the retrieved role.
|
||||||
|
- `principal_ids` (Set of String) The list of principal (user or group) IDs added as principals on the role.
|
||||||
|
- `scope` (List of Object) (see [below for nested schema](#nestedatt--scope))
|
||||||
|
|
||||||
|
<a id="nestedatt--scope"></a>
|
||||||
|
### Nested Schema for `scope`
|
||||||
|
|
||||||
|
Read-Only:
|
||||||
|
|
||||||
|
- `description` (String)
|
||||||
|
- `id` (String)
|
||||||
|
- `name` (String)
|
||||||
|
- `parent_scope_id` (String)
|
||||||
|
- `type` (String)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Role from the global scope
|
||||||
|
data "boundary_role" "global_role" {
|
||||||
|
name = "global_role_one"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Role from an org scope
|
||||||
|
data "boundary_scope" "org" {
|
||||||
|
name = "org_one"
|
||||||
|
scope_id = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "boundary_role" "org_role" {
|
||||||
|
name = "org_role_one"
|
||||||
|
scope_id = data.boundary_scope.org.id
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api"
|
||||||
|
"github.com/hashicorp/boundary/api/roles"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceRole() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Description: "The boundary_role data source allows you to find a Boundary role.",
|
||||||
|
ReadContext: dataSourceRoleRead,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
NameKey: {
|
||||||
|
Description: "The name of the role to retrieve.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringIsNotEmpty,
|
||||||
|
},
|
||||||
|
ScopeIdKey: {
|
||||||
|
Description: "The scope ID in which the resource is created. Defaults `global` if unset.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "global",
|
||||||
|
ValidateFunc: validation.StringIsNotEmpty,
|
||||||
|
},
|
||||||
|
IDKey: {
|
||||||
|
Description: "The ID of the retrieved role.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
DescriptionKey: {
|
||||||
|
Description: "The description of the retrieved role.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
ScopeKey: {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
IDKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
NameKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
TypeKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
DescriptionKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
ParentScopeIdKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rolePrincipalIdsKey: {
|
||||||
|
Description: "The list of principal (user or group) IDs added as principals on the role.",
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
roleGrantStringsKey: {
|
||||||
|
Description: "The list of stringified grants for the role.",
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
roleGrantScopeIdsKey: {
|
||||||
|
Description: "The list of scope IDs for the role's grants.",
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
|
||||||
|
name := d.Get(NameKey).(string)
|
||||||
|
scopeId := d.Get(ScopeIdKey).(string)
|
||||||
|
|
||||||
|
rcl := roles.NewClient(md.client)
|
||||||
|
rolesList, err := rcl.List(ctx, scopeId,
|
||||||
|
roles.WithFilter(FilterWithItemNameMatches(name)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error calling list role: %v", err)
|
||||||
|
}
|
||||||
|
roles := rolesList.GetItems()
|
||||||
|
if roles == nil {
|
||||||
|
return diag.Errorf("no roles found")
|
||||||
|
}
|
||||||
|
if len(roles) == 0 {
|
||||||
|
return diag.Errorf("no matching role found")
|
||||||
|
}
|
||||||
|
if len(roles) > 1 {
|
||||||
|
return diag.Errorf("error found more than 1 role")
|
||||||
|
}
|
||||||
|
|
||||||
|
rrr, err := rcl.Read(ctx, roles[0].Id)
|
||||||
|
if err != nil {
|
||||||
|
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return diag.Errorf("error calling read role: %v", err)
|
||||||
|
}
|
||||||
|
if rrr == nil {
|
||||||
|
return diag.Errorf("role nil after read")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromRoleRead(d, *rrr.Item); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFromRoleRead(d *schema.ResourceData, role roles.Role) error {
|
||||||
|
if err := d.Set(NameKey, role.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(DescriptionKey, role.Description); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(ScopeIdKey, role.ScopeId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(roleGrantStringsKey, role.GrantStrings); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(roleGrantScopeIdsKey, role.GrantScopeIds); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(rolePrincipalIdsKey, role.PrincipalIds); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set(ScopeKey, flattenScopeInfo(role.Scope))
|
||||||
|
d.SetId(role.Id)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/testing/controller"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testRoleName = "my_role"
|
||||||
|
)
|
||||||
|
|
||||||
|
var roleReadGlobal = fmt.Sprintf(`
|
||||||
|
resource "boundary_user" "user" {
|
||||||
|
name = "my_user"
|
||||||
|
scope_id = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_role" "role" {
|
||||||
|
name = "%s"
|
||||||
|
description = "test role global"
|
||||||
|
scope_id = "global"
|
||||||
|
grant_strings = [
|
||||||
|
"ids=*;type=*;actions=read"
|
||||||
|
]
|
||||||
|
principal_ids = [ boundary_user.user.id ]
|
||||||
|
}
|
||||||
|
|
||||||
|
data "boundary_role" "role" {
|
||||||
|
depends_on = [ boundary_role.role ]
|
||||||
|
name = "%s"
|
||||||
|
}
|
||||||
|
`, testRoleName, testRoleName)
|
||||||
|
|
||||||
|
var roleReadOrg = fmt.Sprintf(`
|
||||||
|
resource "boundary_user" "user" {
|
||||||
|
name = "my_user"
|
||||||
|
scope_id = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_role" "role" {
|
||||||
|
name = "%s"
|
||||||
|
description = "test role org"
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
grant_strings = [
|
||||||
|
"ids=*;type=*;actions=read"
|
||||||
|
]
|
||||||
|
principal_ids = [ boundary_user.user.id ]
|
||||||
|
}
|
||||||
|
|
||||||
|
data "boundary_role" "role" {
|
||||||
|
depends_on = [ boundary_role.role ]
|
||||||
|
name = "%s"
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
}
|
||||||
|
`, testRoleName, testRoleName)
|
||||||
|
|
||||||
|
func TestAccRoleReadGlobal(t *testing.T) {
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
defer tc.Shutdown()
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
dataSourceName := "data.boundary_role.role"
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testConfig(url, roleReadGlobal),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, IDKey),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, ScopeIdKey),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, NameKey, testRoleName),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, DescriptionKey),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", roleGrantStringsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.0", roleGrantStringsKey), "ids=*;type=*;actions=read"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", roleGrantScopeIdsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, "scope.0.id"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.name", "global"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.type", "global"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", rolePrincipalIdsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttrPair(dataSourceName, fmt.Sprintf("%s.0", rolePrincipalIdsKey), "boundary_user.user", "id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccRoleReadOrg(t *testing.T) {
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
defer tc.Shutdown()
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
dataSourceName := "data.boundary_role.role"
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testConfig(url, fooOrg, roleReadOrg),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, IDKey),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, ScopeIdKey),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, NameKey, testRoleName),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, DescriptionKey),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", roleGrantStringsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.0", roleGrantStringsKey), "ids=*;type=*;actions=read"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", roleGrantScopeIdsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttrSet(dataSourceName, "scope.0.id"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.name", "org1"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.type", "org"),
|
||||||
|
resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("%s.#", rolePrincipalIdsKey), "1"),
|
||||||
|
resource.TestCheckResourceAttrPair(dataSourceName, fmt.Sprintf("%s.0", rolePrincipalIdsKey), "boundary_user.user", "id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -137,6 +137,7 @@ func New() *schema.Provider {
|
|||||||
"boundary_group": dataSourceGroup(),
|
"boundary_group": dataSourceGroup(),
|
||||||
"boundary_scope": dataSourceScope(),
|
"boundary_scope": dataSourceScope(),
|
||||||
"boundary_user": dataSourceUser(),
|
"boundary_user": dataSourceUser(),
|
||||||
|
"boundary_role": dataSourceRole(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user