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 scope datasource, tests, and docs #474

Merged
merged 2 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions docs/data-sources/scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
# 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.

## 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