Skip to content

Commit

Permalink
add scope datasource, tests, and docs (#474)
Browse files Browse the repository at this point in the history
* add scope datasource, tests, and docs

* add details on the global scope to docs
  • Loading branch information
grantorchard authored Oct 11, 2023
1 parent afbc61a commit c3b08a1
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 0 deletions.
42 changes: 42 additions & 0 deletions docs/data-sources/scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_scope Data Source - terraform-provider-boundary"
subcategory: ""
description: |-
The scope data source allows you to discover an existing Boundary scope by name.
---

# boundary_scope (Data Source)

The scope data source allows you to discover an existing Boundary scope by name.
Please note that the Global scope will always have an id of "global", and does not need to be discovered with this data source.

## Example Usage

Basic usage:

```terraform
data "boundary_scope" "org" {
name = "SecOps"
parent_scope_id = "global"
}
data "boundary_scope" "project" {
name = "2111"
parent_scope_id = data.boundary_scope.id
}
```


<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) The name of the scope to retrieve.
- `scope_id` (String) The parent scope ID that will be queried for the scope.

### Read-Only

- `description` (String) The description of the retrieved scope.
- `id` (String) The ID of the retrieved scope.
10 changes: 10 additions & 0 deletions examples/data-sources/scope/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Retrieve the ID of a Boundary project
data "boundary_scope" "org" {
name = "SecOps"
parent_scope_id = "global"
}

data "boundary_scope" "project" {
name = "2111"
parent_scope_id = data.boundary_scope.id
}
112 changes: 112 additions & 0 deletions internal/provider/data_source_scope.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package provider

import (
"context"
"net/http"

"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceScope() *schema.Resource {
return &schema.Resource{
Description: "The scope data source allows you to discover an existing Boundary scope by name.",
ReadContext: dataSourceScopeRead,

Schema: map[string]*schema.Schema{
IDKey: {
Description: "The ID of the retrieved scope.",
Type: schema.TypeString,
Computed: true,
},
NameKey: {
Description: "The name of the scope to retrieve.",
Type: schema.TypeString,
Required: true,
},
DescriptionKey: {
Description: "The description of the retrieved scope.",
Type: schema.TypeString,
Computed: true,
},
ScopeIdKey: {
Description: "The parent scope ID that will be queried for the scope.",
Type: schema.TypeString,
Required: true,
},
},
}
}

func dataSourceScopeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
opts := []scopes.Option{}

var name string
if v, ok := d.GetOk(NameKey); ok {
name = v.(string)
} else {
return diag.Errorf("no name provided")
}

var scopeId string
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
scopeId = scopeIdVal.(string)
} else {
return diag.Errorf("no parent scope ID provided")
}

scp := scopes.NewClient(md.client)

scpls, err := scp.List(ctx, scopeId, opts...)
if err != nil {
return diag.Errorf("error calling read scope: %v", err)
}
if scpls == nil {
return diag.Errorf("no scopes found")
}

var scopeIdRead string
for _, scopeItem := range scpls.GetItems() {
if scopeItem.Name == name {
scopeIdRead = scopeItem.Id
break
}
}

if scopeIdRead == "" {
return diag.Errorf("scope name %v not found in scope list", err)
}

srr, err := scp.Read(ctx, scopeIdRead)
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 scope: %v", err)
}
if srr == nil {
return diag.Errorf("scope nil after read")
}

if err := setFromScopeReadResponseMap(d, srr.GetResponse().Map); err != nil {
return diag.FromErr(err)
}

return nil
}

func setFromScopeReadResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
if err := d.Set(NameKey, raw["name"]); err != nil {
return err
}
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
return err
}

d.SetId(raw["id"].(string))
return nil
}
95 changes: 95 additions & 0 deletions internal/provider/data_source_scope_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
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 (
orgName = "test org scope"
projectName = "test project scope"
notProjectName = "test project scope with wrong name"
scopeDesc = "created to test the scope datasource"
)

var (
scopeCreateAndRead = fmt.Sprintf(`
resource "boundary_scope" "global" {
global_scope = true
name = "global"
description = "Global Scope"
scope_id = "global"
}
resource "boundary_scope" "org" {
scope_id = boundary_scope.global.id
name = "%s"
description = "%s"
}
resource "boundary_scope" "project" {
depends_on = [boundary_role.org_admin]
scope_id = boundary_scope.org.id
name = "%s"
description = "%s"
}
resource "boundary_role" "org_admin" {
scope_id = "global"
grant_scope_id = boundary_scope.org.id
grant_strings = ["id=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
data "boundary_scope" "org" {
depends_on = [boundary_scope.org]
scope_id = "global"
name = "%s"
}
data "boundary_scope" "project" {
depends_on = [boundary_scope.project]
scope_id = data.boundary_scope.org.id
name = "%s"
}`, orgName, scopeDesc, projectName, scopeDesc, orgName, projectName)
)

func TestAccScopeRead(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]

var provider *schema.Provider
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckScopeResourceDestroy(t, provider),
Steps: []resource.TestStep{
{
// create and read
Config: testConfig(url, scopeCreateAndRead),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org"),
resource.TestCheckResourceAttr("boundary_scope.org", "description", scopeDesc),
resource.TestCheckResourceAttr("boundary_scope.org", "name", orgName),
testAccCheckScopeResourceExists(provider, "boundary_scope.project"),
resource.TestCheckResourceAttr("boundary_scope.project", "description", scopeDesc),
resource.TestCheckResourceAttr("boundary_scope.project", "name", projectName),
// Check attributes on the org datasource
resource.TestCheckResourceAttrSet("data.boundary_scope.org", "scope_id"),
resource.TestCheckResourceAttrSet("data.boundary_scope.org", "id"),
resource.TestCheckResourceAttr("data.boundary_scope.org", "name", orgName),
resource.TestCheckResourceAttr("data.boundary_scope.org", "description", scopeDesc),
// Check attributes on the project datasource
resource.TestCheckResourceAttrSet("data.boundary_scope.project", "scope_id"),
resource.TestCheckResourceAttrSet("data.boundary_scope.project", "id"),
resource.TestCheckResourceAttr("data.boundary_scope.project", "name", projectName),
resource.TestCheckResourceAttr("data.boundary_scope.project", "description", scopeDesc),
),
},
},
})
}
3 changes: 3 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ func New() *schema.Provider {
"boundary_user": resourceUser(),
"boundary_worker": resourceWorker(),
},
DataSourcesMap: map[string]*schema.Resource{
"boundary_scope": dataSourceScope(),
},
}

p.ConfigureContextFunc = providerConfigure(p)
Expand Down

0 comments on commit c3b08a1

Please sign in to comment.