New Data source data.boundary_user (#468)

This commit is contained in:
drewmullen authored and GitHub committed 2023-10-17 16:36:51 -07:00
1 parent b06da56d75
commit 0f2473a1d7
16 files changed
+478 -27

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch a test function",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": [
"-test.v",
"-test.run",
"^${selectedText}$"
],
"showLog": true,
"envFile": "${workspaceFolder}/.vscode/private.env"
}
]
}
+3
View File
@@ -0,0 +1,3 @@
TF_ACC=1
TF_LOG=INFO
GOFLAGS='-mod=readonly'
+32 -22
View File
@@ -1,18 +1,15 @@
![](boundary.png) ![](boundary.png)
Terraform Provider Boundary # Terraform Provider Boundary
==================
Available in the [Terraform Registry](https://registry.terraform.io/providers/hashicorp/boundary/latest). Available in the [Terraform Registry](https://registry.terraform.io/providers/hashicorp/boundary/latest).
Requirements ## Requirements
------------
- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x - [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x
- [Go](https://golang.org/doc/install) >= 1.20 - [Go](https://golang.org/doc/install) >= 1.20
Building The Provider ## Building The Provider
---------------------
1. Clone the repository 1. Clone the repository
1. Enter the repository directory 1. Enter the repository directory
@@ -22,32 +19,30 @@ You'll need to ensure that your Terraform file contains the information necessar
```hcl ```hcl
terraform { terraform {
required_providers { required_providers {
boundary = { boundary = {
source = "localhost/providers/boundary" source = "localhost/providers/boundary"
version = "0.0.1" version = "0.0.1"
} }
} }
} }
``` ```
Adding Dependencies ## Adding Dependencies
---------------------
This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). This provider uses [Go modules](https://github.com/golang/go/wiki/Modules).
Please see the Go documentation for the most up to date information about using Go modules. Please see the Go documentation for the most up to date information about using Go modules.
To add a new dependency `github.com/author/dependency` to your Terraform provider: To add a new dependency `github.com/author/dependency` to your Terraform provider:
``` ```shell
go get github.com/author/dependency go get github.com/author/dependency
go mod tidy go mod tidy
``` ```
Then commit the changes to `go.mod` and `go.sum`. Then commit the changes to `go.mod` and `go.sum`.
Developing the Provider ## Developing the Provider
---------------------------
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above). If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
@@ -72,17 +67,32 @@ $ make testacc
For more details on the docker image and troubleshooting see the For more details on the docker image and troubleshooting see the
[boundary testing doc](https://github.com/hashicorp/boundary/blob/main/CONTRIBUTING.md#testing). [boundary testing doc](https://github.com/hashicorp/boundary/blob/main/CONTRIBUTING.md#testing).
Generating Docs ## Debugging the provider
----------------------
If you're using vscode, this provider has delve debugging baked into the [.vscode](https://github.com/hashicorp/terraform-provider-boundary/tree/main/.vscode) directory. To debug you can find instructions [here.](https://dev.to/drewmullen/vscode-terraform-provider-development-setup-debugging-6bn#usage)
## Generating Docs
This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. Each resource and data source requires a [templates](https://github.com/hashicorp/terraform-provider-boundary/tree/main/templates) and [examples](https://github.com/hashicorp/terraform-provider-boundary/tree/main/examples) then you execute a binary generate the docs which are placed in [./docs](https://github.com/hashicorp/terraform-provider-boundary/tree/main/docs).
### New Resources & Data Sources (documentation templates)
If you're adding a new resource or a data source, you must include a documentation template for your new R/DS in [./templates](https://github.com/hashicorp/terraform-provider-boundary/tree/main/templates) directory. This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. For full details see the link.
### Documentation Examples for Resources & Data Sources
Examples are required for all resources and data sources. This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. To add examples, add a new file to the [./examples](https://github.com/hashicorp/terraform-provider-boundary/tree/main/examples) directory or update the existing files. Next make sure the corresponding template in [./templates](https://github.com/hashicorp/terraform-provider-boundary/tree/main/templates) directory references this example.
### Generating
From the root of the repo run: From the root of the repo run:
``` ```shell
go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
``` ```
Using the provider ## Using the provider
----------------------
Please see our detailed docs for individual resource usage. Below is a complex example using the Boundary provider to configure all resource types available: Please see our detailed docs for individual resource usage. Below is a complex example using the Boundary provider to configure all resource types available:
```hcl ```hcl
+3 -3
View File
@@ -1,5 +1,4 @@
--- ---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_scope Data Source - terraform-provider-boundary" page_title: "boundary_scope Data Source - terraform-provider-boundary"
subcategory: "" subcategory: ""
description: |- description: |-
@@ -9,18 +8,19 @@ description: |-
# boundary_scope (Data Source) # boundary_scope (Data Source)
The scope data source allows you to discover an existing Boundary scope by name. 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 ## Example Usage
```terraform ```terraform
# Retrieve the ID of a Boundary project # Retrieve the ID of a Boundary project
data "boundary_scope" "org" { data "boundary_scope" "org" {
name = "SecOps" name = "SecOps"
parent_scope_id = "global" parent_scope_id = "global"
} }
data "boundary_scope" "project" { data "boundary_scope" "project" {
name = "2111" name = "2111"
parent_scope_id = data.boundary_scope.id parent_scope_id = data.boundary_scope.id
} }
``` ```
+64
View File
@@ -0,0 +1,64 @@
---
page_title: "boundary_user Data Source - terraform-provider-boundary"
subcategory: ""
description: |-
The user data source allows you to find a Boundary user.
---
# boundary_user (Data Source)
The user data source allows you to find a Boundary user.
## Example Usage
```terraform
# Retrieve a user from the global scope
data "boundary_user" "global_scope_admin" {
name = "admin"
}
# User from a org scope
data "boundary_user" "org_user" {
name = "username"
scope_id = data.boundary_scope.org.id
}
data "boundary_scope" "org" {
name = "my-org"
parent_scope_id = data.boundary_scope.org.id
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `name` (String) The username to search for.
### Optional
- `scope_id` (String) The scope ID in which the resource is created. Defaults `global` if unset.
### Read-Only
- `account_ids` (Set of String) Account ID's to associate with this user resource.
- `authorized_actions` (List of String) A list of actions that the worker is entitled to perform.
- `description` (String) The user description.
- `id` (String) The ID of the user.
- `login_name` (String) Login name for user.
- `primary_account_id` (String) Primary account ID.
- `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)
@@ -1,10 +1,10 @@
# Retrieve the ID of a Boundary project # Retrieve the ID of a Boundary project
data "boundary_scope" "org" { data "boundary_scope" "org" {
name = "SecOps" name = "SecOps"
parent_scope_id = "global" parent_scope_id = "global"
} }
data "boundary_scope" "project" { data "boundary_scope" "project" {
name = "2111" name = "2111"
parent_scope_id = data.boundary_scope.id parent_scope_id = data.boundary_scope.id
} }
@@ -0,0 +1,17 @@
# Retrieve a user from the global scope
data "boundary_user" "global_scope_admin" {
name = "admin"
}
# User from a org scope
data "boundary_user" "org_user" {
name = "username"
scope_id = data.boundary_scope.org.id
}
data "boundary_scope" "org" {
name = "my-org"
parent_scope_id = data.boundary_scope.org.id
}
+1
View File
@@ -3,6 +3,7 @@ module github.com/hashicorp/terraform-provider-boundary
go 1.21 go 1.21
require ( require (
github.com/YakDriver/regexache v0.23.0
github.com/hashicorp/boundary v0.13.1-0.20231012004550-1ed0a13004b9 github.com/hashicorp/boundary v0.13.1-0.20231012004550-1ed0a13004b9
github.com/hashicorp/boundary/api v0.0.41 github.com/hashicorp/boundary/api v0.0.41
github.com/hashicorp/boundary/sdk v0.0.37 github.com/hashicorp/boundary/sdk v0.0.37
+2
View File
@@ -59,6 +59,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/YakDriver/regexache v0.23.0 h1:kv3j4XKhbx/vqUilSBgizXDUXHvvH1KdYekdmGwz4C4=
github.com/YakDriver/regexache v0.23.0/go.mod h1:K4BZ3MYKAqSFbYWqmbsG+OzYUDyJjnMEr27DJEsVG3U=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
+5
View File
@@ -46,4 +46,9 @@ const (
internalForceUpdateKey = "internal_force_update" internalForceUpdateKey = "internal_force_update"
// workerFilter is used for common "worker_filter" resource attribute // workerFilter is used for common "worker_filter" resource attribute
WorkerFilterKey = "worker_filter" WorkerFilterKey = "worker_filter"
// common User arguments
LoginNameKey = "login_name"
PrimaryAccountID = "primary_account_id"
ScopeKey = "scope"
ParentScopeId = "parent_scope_id"
) )
+188
View File
@@ -0,0 +1,188 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/api/users"
"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 dataSourceUser() *schema.Resource {
return &schema.Resource{
Description: "The user data source allows you to find a Boundary user.",
ReadContext: dataSourceUserRead,
Schema: map[string]*schema.Schema{
IDKey: {
Description: "The ID of the user.",
Type: schema.TypeString,
Computed: true,
},
NameKey: {
Description: "The username to search for.",
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},
DescriptionKey: {
Description: "The user description.",
Type: schema.TypeString,
Computed: true,
},
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,
},
userAccountIDsKey: {
Description: "Account ID's to associate with this user resource.",
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
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,
},
ParentScopeId: {
Type: schema.TypeString,
Computed: true,
},
},
},
},
authorizedActions: {
Description: "A list of actions that the worker is entitled to perform.",
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
},
LoginNameKey: {
Description: "Login name for user.",
Type: schema.TypeString,
Computed: true,
},
PrimaryAccountID: {
Description: "Primary account ID.",
Type: schema.TypeString,
Computed: true,
},
},
}
}
func dataSourceUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
usrs := users.NewClient(md.client)
opts := []users.Option{}
// Get user ID using name
name := d.Get(NameKey).(string)
scopeID := d.Get(ScopeIdKey).(string)
opts = append(opts, users.WithFilter(FilterWithItemNameMatches(name)))
usersList, err := usrs.List(ctx, scopeID, opts...)
if err != nil {
return diag.Errorf("error calling list user: %v", err)
}
users := usersList.GetItems()
// check length, 0 means no user, > 1 means too many
if len(users) == 0 {
return diag.Errorf("no matching user found: %v", err)
}
if len(users) > 1 {
return diag.Errorf("error found more than 1 user: %v", err)
}
if err := setFromUserItem(d, *users[0]); err != nil {
return diag.FromErr(err)
}
return nil
}
func setFromUserItem(d *schema.ResourceData, user users.User) error {
if err := d.Set(NameKey, user.Name); err != nil {
return err
}
if err := d.Set(DescriptionKey, user.Description); err != nil {
return err
}
if err := d.Set(ScopeIdKey, user.ScopeId); err != nil {
return err
}
if err := d.Set(userAccountIDsKey, user.AccountIds); err != nil {
return err
}
if err := d.Set(authorizedActions, user.AuthorizedActions); err != nil {
return err
}
if err := d.Set(LoginNameKey, user.LoginName); err != nil {
return err
}
if err := d.Set(PrimaryAccountID, user.PrimaryAccountId); err != nil {
return err
}
d.Set(ScopeKey, flattenScopeInfo(user.Scope))
d.SetId(user.Id)
return nil
}
func flattenScopeInfo(scope *scopes.ScopeInfo) []interface{} {
if scope == nil {
return []interface{}{}
}
m := make(map[string]interface{})
if v := scope.Id; v != "" {
m[IDKey] = v
}
if v := scope.Type; v != "" {
m[TypeKey] = v
}
if v := scope.Description; v != "" {
m[DescriptionKey] = v
}
if v := scope.ParentScopeId; v != "" {
m[ParentScopeId] = v
}
if v := scope.Name; v != "" {
m[NameKey] = v
}
return []interface{}{m}
}
@@ -0,0 +1,95 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"fmt"
"testing"
"github.com/YakDriver/regexache"
"github.com/hashicorp/boundary/testing/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
var (
orgUserDataSource = fmt.Sprintf(`
resource "boundary_user" "org1" {
name = "test"
description = "%s"
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
}
data "boundary_user" "org1" {
name = "test"
scope_id = boundary_scope.org1.id
depends_on = [boundary_user.org1]
}`, fooDescription)
globalUserDataSource = `
data "boundary_user" "admin" {
name = "admin"
depends_on = [boundary_role.org1_admin]
}`
)
// NOTE: this test also tests out the direct token auth mechanism.
func TestAccUserDataSource_basicOrgUser(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]
token := tc.Token().Token
resourceName := "boundary_user.org1"
dataSourceName := "data.boundary_user.org1"
var provider *schema.Provider
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckUserResourceDestroy(t, provider),
Steps: []resource.TestStep{
{
// test create
Config: testConfigWithToken(url, token, fooOrg, orgUserDataSource),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserResourceExists(provider, resourceName),
resource.TestCheckResourceAttr(dataSourceName, DescriptionKey, fooDescription),
resource.TestCheckResourceAttr(dataSourceName, NameKey, "test"),
),
},
},
})
}
func TestAccUserDataSource_globalAdminUser(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]
token := tc.Token().Token
dataSourceName := "data.boundary_user.admin"
var provider *schema.Provider
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories(&provider),
Steps: []resource.TestStep{
{
Config: testConfigWithToken(url, token, fooOrg, globalUserDataSource),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, NameKey, "admin"),
resource.TestCheckResourceAttr(dataSourceName, DescriptionKey, "Initial admin user within the \"global\" scope"),
resource.TestCheckResourceAttr(dataSourceName, LoginNameKey, "testuser"),
resource.TestMatchResourceAttr(dataSourceName, IDKey, regexache.MustCompile(`^u_.+`)),
resource.TestMatchResourceAttr(dataSourceName, PrimaryAccountID, regexache.MustCompile(`^acctpw_.+`)),
resource.TestCheckResourceAttr(dataSourceName, "authorized_actions.#", "7"),
resource.TestCheckResourceAttr(dataSourceName, "scope.0.name", "global"),
resource.TestCheckResourceAttr(dataSourceName, "scope.0.id", "global"),
resource.TestCheckResourceAttr(dataSourceName, "scope.0.type", "global"),
resource.TestCheckResourceAttr(dataSourceName, "scope.0.description", "Global Scope"),
),
},
},
})
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import "fmt"
func FilterWithItemNameMatches(name string) string {
return fmt.Sprintf("\"/item/name\" matches \"%s\"", name)
}
+1
View File
@@ -129,6 +129,7 @@ func New() *schema.Provider {
}, },
DataSourcesMap: map[string]*schema.Resource{ DataSourcesMap: map[string]*schema.Resource{
"boundary_scope": dataSourceScope(), "boundary_scope": dataSourceScope(),
"boundary_user": dataSourceUser(),
}, },
} }
+17
View File
@@ -0,0 +1,17 @@
---
page_title: "boundary_scope Data Source - terraform-provider-boundary"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---
# boundary_scope (Data Source)
{{ .Description | trimspace }}
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
{{tffile "examples/data-sources/boundary_scope/data-source.tf"}}
{{ .SchemaMarkdown | trimspace }}
+16
View File
@@ -0,0 +1,16 @@
---
page_title: "boundary_user Data Source - terraform-provider-boundary"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---
# boundary_user (Data Source)
{{ .Description | trimspace }}
## Example Usage
{{tffile "examples/data-sources/boundary_user/data-source.tf"}}
{{ .SchemaMarkdown | trimspace }}