diff --git a/docs/data-sources/auth_method.md b/docs/data-sources/auth_method.md new file mode 100644 index 00000000..df67562d --- /dev/null +++ b/docs/data-sources/auth_method.md @@ -0,0 +1,60 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "boundary_auth_method Data Source - terraform-provider-boundary" +subcategory: "" +description: |- + The boundaryauthmethod data source allows you to find a Boundary auth method. +--- + +# boundary_auth_method (Data Source) + +The boundary_auth_method data source allows you to find a Boundary auth method. + +## Example Usage + +```terraform +# Retrieve an auth method from the global scope +data "boundary_auth_method" "auth_method" { + name = "password_auth_method" +} + +# Auth method from a org scope +data "boundary_scope" "org" { + name = "my-org" + scope_id = "global" +} + +data "boundary_auth_method" "auth_method" { + name = "password_auth_method" + scope_id = data.boundary_scope.org.id +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the auth method 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 auth method. +- `id` (String) The ID of the retrieved auth method. +- `scope` (List of Object) (see [below for nested schema](#nestedatt--scope)) +- `type` (String) The type of the auth method + + +### Nested Schema for `scope` + +Read-Only: + +- `description` (String) +- `id` (String) +- `name` (String) +- `parent_scope_id` (String) +- `type` (String) diff --git a/examples/data-sources/boundary_auth_method/data-source.tf b/examples/data-sources/boundary_auth_method/data-source.tf new file mode 100644 index 00000000..ad835a50 --- /dev/null +++ b/examples/data-sources/boundary_auth_method/data-source.tf @@ -0,0 +1,15 @@ +# Retrieve an auth method from the global scope +data "boundary_auth_method" "auth_method" { + name = "password_auth_method" +} + +# Auth method from a org scope +data "boundary_scope" "org" { + name = "my-org" + scope_id = "global" +} + +data "boundary_auth_method" "auth_method" { + name = "password_auth_method" + scope_id = data.boundary_scope.org.id +} diff --git a/internal/provider/data_source_auth_method.go b/internal/provider/data_source_auth_method.go new file mode 100644 index 00000000..657c3bf8 --- /dev/null +++ b/internal/provider/data_source_auth_method.go @@ -0,0 +1,142 @@ +// 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/authmethods" + "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 dataSourceAuthMethod() *schema.Resource { + return &schema.Resource{ + Description: "The boundary_auth_method data source allows you to find a Boundary auth method.", + ReadContext: dataSourceAuthMethodRead, + + Schema: map[string]*schema.Schema{ + NameKey: { + Description: "The name of the auth method 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 auth method.", + Type: schema.TypeString, + Computed: true, + }, + DescriptionKey: { + Description: "The description of the retrieved auth method.", + Type: schema.TypeString, + Computed: true, + }, + TypeKey: { + Description: "The type of the auth method", + 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, + }, + }, + }, + }, + }, + } +} + +func dataSourceAuthMethodRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + md := meta.(*metaData) + + name := d.Get(NameKey).(string) + scopeId := d.Get(ScopeIdKey).(string) + + amcl := authmethods.NewClient(md.client) + authMethodsList, err := amcl.List(ctx, scopeId, + authmethods.WithFilter(FilterWithItemNameMatches(name)), + ) + if err != nil { + return diag.Errorf("error calling list auth method: %v", err) + } + authMethods := authMethodsList.GetItems() + if authMethods == nil { + return diag.Errorf("no auth methods found") + } + if len(authMethods) == 0 { + return diag.Errorf("no matching auth method found") + } + if len(authMethods) > 1 { + return diag.Errorf("error found more than 1 auth method") + } + + amrr, err := amcl.Read(ctx, authMethods[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 auth method: %v", err) + } + if amrr == nil { + return diag.Errorf("auth method nil after read") + } + + if err := setFromAuthMethodRead(d, *amrr.Item); err != nil { + return diag.FromErr(err) + } + + return nil +} + +func setFromAuthMethodRead(d *schema.ResourceData, authMethod authmethods.AuthMethod) error { + if err := d.Set(NameKey, authMethod.Name); err != nil { + return err + } + if err := d.Set(DescriptionKey, authMethod.Description); err != nil { + return err + } + if err := d.Set(ScopeIdKey, authMethod.ScopeId); err != nil { + return err + } + if err := d.Set(TypeKey, authMethod.Type); err != nil { + return err + } + d.Set(ScopeKey, flattenScopeInfo(authMethod.Scope)) + d.SetId(authMethod.Id) + return nil +} diff --git a/internal/provider/data_source_auth_method_test.go b/internal/provider/data_source_auth_method_test.go new file mode 100644 index 00000000..c4efb086 --- /dev/null +++ b/internal/provider/data_source_auth_method_test.go @@ -0,0 +1,98 @@ +// 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 ( + testAuthMethodName = "test_auth_method" +) + +var authMethodReadGlobal = fmt.Sprintf(` +resource "boundary_auth_method" "auth_method" { + name = "%s" + description = "test" + scope_id = "global" + type = "password" + depends_on = [boundary_role.org1_admin] +} + +data "boundary_auth_method" "auth_method" { + depends_on = [ boundary_auth_method.auth_method ] + name = "%s" +}`, testAuthMethodName, testAuthMethodName) + +var authMethodReadOrg = fmt.Sprintf(` +resource "boundary_auth_method" "auth_method" { + name = "%s" + description = "test" + scope_id = boundary_scope.org1.id + type = "password" + depends_on = [boundary_role.org1_admin] +} + +data "boundary_auth_method" "auth_method" { + depends_on = [ boundary_auth_method.auth_method ] + name = "%s" + scope_id = boundary_scope.org1.id +}`, testAuthMethodName, testAuthMethodName) + +func TestAccAuthMethodReadGlobal(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), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooOrg, authMethodReadGlobal), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", IDKey), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", ScopeIdKey), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", NameKey, testAuthMethodName), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", TypeKey, "password"), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", DescriptionKey), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", "scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", "scope.0.name", "global"), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", "scope.0.type", "global"), + ), + }, + }, + }) +} + +func TestAccAuthMethodReadOrg(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), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooOrg, authMethodReadOrg), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", IDKey), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", ScopeIdKey), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", NameKey, testAuthMethodName), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", TypeKey, "password"), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", DescriptionKey), + resource.TestCheckResourceAttrSet("data.boundary_auth_method.auth_method", "scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", "scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_auth_method.auth_method", "scope.0.type", "org"), + ), + }, + }, + }) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 1d4ba4ad..56b547e1 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -128,10 +128,11 @@ func New() *schema.Provider { "boundary_worker": resourceWorker(), }, DataSourcesMap: map[string]*schema.Resource{ - "boundary_account": dataSourceAccount(), - "boundary_group": dataSourceGroup(), - "boundary_scope": dataSourceScope(), - "boundary_user": dataSourceUser(), + "boundary_account": dataSourceAccount(), + "boundary_auth_method": dataSourceAuthMethod(), + "boundary_group": dataSourceGroup(), + "boundary_scope": dataSourceScope(), + "boundary_user": dataSourceUser(), }, }