From 5feb16fe15a8bebf7dc56e0a0bb190c4ebf5786d Mon Sep 17 00:00:00 2001 From: Michael Li Date: Thu, 9 May 2024 14:33:16 -0400 Subject: [PATCH] gen --- internal/provider/data_source_accounts.go | 211 +++++ .../provider/data_source_accounts_test.go | 67 ++ internal/provider/data_source_aliases.go | 223 +++++ internal/provider/data_source_auth_methods.go | 218 +++++ .../provider/data_source_auth_methods_test.go | 66 ++ internal/provider/data_source_auth_tokens.go | 220 +++++ .../provider/data_source_auth_tokens_test.go | 53 ++ .../data_source_credential_libraries.go | 207 +++++ .../data_source_credential_libraries_test.go | 76 ++ .../provider/data_source_credential_stores.go | 211 +++++ .../data_source_credential_stores_test.go | 76 ++ internal/provider/data_source_credentials.go | 203 +++++ internal/provider/data_source_groups.go | 232 ++++++ internal/provider/data_source_groups_test.go | 66 ++ .../provider/data_source_host_catalogs.go | 243 ++++++ .../data_source_host_catalogs_test.go | 69 ++ internal/provider/data_source_host_sets.go | 246 ++++++ .../provider/data_source_host_sets_test.go | 95 +++ internal/provider/data_source_hosts.go | 259 ++++++ internal/provider/data_source_hosts_test.go | 84 ++ .../provider/data_source_managed_groups.go | 210 +++++ .../data_source_managed_groups_test.go | 55 ++ internal/provider/data_source_policies.go | 209 +++++ internal/provider/data_source_roles.go | 311 +++++++ internal/provider/data_source_roles_test.go | 69 ++ internal/provider/data_source_scopes.go | 220 +++++ internal/provider/data_source_scopes_test.go | 52 ++ .../data_source_session_recordings.go | 761 ++++++++++++++++++ internal/provider/data_source_sessions.go | 320 ++++++++ .../provider/data_source_sessions_test.go | 33 + .../provider/data_source_storage_buckets.go | 257 ++++++ internal/provider/data_source_targets.go | 449 +++++++++++ internal/provider/data_source_targets_test.go | 88 ++ internal/provider/data_source_users.go | 247 ++++++ internal/provider/data_source_users_test.go | 71 ++ internal/provider/data_source_workers.go | 207 +++++ internal/provider/provider.go | 25 +- 37 files changed, 6704 insertions(+), 5 deletions(-) create mode 100644 internal/provider/data_source_accounts.go create mode 100644 internal/provider/data_source_accounts_test.go create mode 100644 internal/provider/data_source_aliases.go create mode 100644 internal/provider/data_source_auth_methods.go create mode 100644 internal/provider/data_source_auth_methods_test.go create mode 100644 internal/provider/data_source_auth_tokens.go create mode 100644 internal/provider/data_source_auth_tokens_test.go create mode 100644 internal/provider/data_source_credential_libraries.go create mode 100644 internal/provider/data_source_credential_libraries_test.go create mode 100644 internal/provider/data_source_credential_stores.go create mode 100644 internal/provider/data_source_credential_stores_test.go create mode 100644 internal/provider/data_source_credentials.go create mode 100644 internal/provider/data_source_groups.go create mode 100644 internal/provider/data_source_groups_test.go create mode 100644 internal/provider/data_source_host_catalogs.go create mode 100644 internal/provider/data_source_host_catalogs_test.go create mode 100644 internal/provider/data_source_host_sets.go create mode 100644 internal/provider/data_source_host_sets_test.go create mode 100644 internal/provider/data_source_hosts.go create mode 100644 internal/provider/data_source_hosts_test.go create mode 100644 internal/provider/data_source_managed_groups.go create mode 100644 internal/provider/data_source_managed_groups_test.go create mode 100644 internal/provider/data_source_policies.go create mode 100644 internal/provider/data_source_roles.go create mode 100644 internal/provider/data_source_roles_test.go create mode 100644 internal/provider/data_source_scopes.go create mode 100644 internal/provider/data_source_scopes_test.go create mode 100644 internal/provider/data_source_session_recordings.go create mode 100644 internal/provider/data_source_sessions.go create mode 100644 internal/provider/data_source_sessions_test.go create mode 100644 internal/provider/data_source_storage_buckets.go create mode 100644 internal/provider/data_source_targets.go create mode 100644 internal/provider/data_source_targets_test.go create mode 100644 internal/provider/data_source_users.go create mode 100644 internal/provider/data_source_users_test.go create mode 100644 internal/provider/data_source_workers.go diff --git a/internal/provider/data_source_accounts.go b/internal/provider/data_source_accounts.go new file mode 100644 index 00000000..378f5dcc --- /dev/null +++ b/internal/provider/data_source_accounts.go @@ -0,0 +1,211 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceAccountsSchema = map[string]*schema.Schema{ + "auth_method_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the auth method whose accounts should be listed.", + }, + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The list of accounts.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_method_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the auth method that is associated with this account.", + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the account.", + }, + "managed_group_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of this account. If you do not set an account type, Boundary infers it from the type of the auth method.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation fails if the version does not match the latest known good version.\nVersion is not required when you create an account.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceAccounts() *schema.Resource { + return &schema.Resource{ + Description: "Lists accounts", + ReadContext: dataSourceAccountsRead, + Schema: dataSourceAccountsSchema, + } +} + +func dataSourceAccountsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "accounts", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + if d.Get("auth_method_id") != "" { + q.Add("auth_method_id", d.Get("auth_method_id").(string)) + } + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("auth_method_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceAccountsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-accounts") + + return nil +} diff --git a/internal/provider/data_source_accounts_test.go b/internal/provider/data_source_accounts_test.go new file mode 100644 index 00000000..13c220a7 --- /dev/null +++ b/internal/provider/data_source_accounts_test.go @@ -0,0 +1,67 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + fooAccountDataMissingAuthMethodId = ` +data "boundary_accounts" "foo" {} +` + + fooAccountData = ` +data "boundary_accounts" "foo" { + depends_on = [boundary_account.foo] + auth_method_id = boundary_auth_method.foo.id +} +` +) + +func TestAccDataSourceAccounts(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, fooAccountDataMissingAuthMethodId), + ExpectError: regexp.MustCompile("Invalid formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, fooAccount, fooAccountData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "auth_method_id"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.%", "11"), + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.auth_method_id"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.authorized_actions.#", "6"), + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.description", "test account"), + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.managed_group_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.0.description", ""), + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.0.parent_scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.scope.0.type", "org"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.type", "password"), + resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.version", "1"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_aliases.go b/internal/provider/data_source_aliases.go new file mode 100644 index 00000000..502dc37c --- /dev/null +++ b/internal/provider/data_source_aliases.go @@ -0,0 +1,223 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceAliasesSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The list of aliases.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set descripton for identification purposes.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "destination_id is the id of the resource that this alias points to.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the alias.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope of which this alias is a part.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "type is the type of the alias.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was last updated.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of the alias. This is the value referenced by the user that\nis resolved to the destination id.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation fails if the version does not match the latest known good version.\nVersion is not required when you create an alias.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to recursively list aliases in the provided scope's child scopes.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the scope in which to list aliases", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceAliases() *schema.Resource { + return &schema.Resource{ + Description: "Lists aliases", + ReadContext: dataSourceAliasesRead, + Schema: dataSourceAliasesSchema, + } +} + +func dataSourceAliasesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "aliases", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceAliasesSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-aliases") + + return nil +} diff --git a/internal/provider/data_source_auth_methods.go b/internal/provider/data_source_auth_methods.go new file mode 100644 index 00000000..c30c0953 --- /dev/null +++ b/internal/provider/data_source_auth_methods.go @@ -0,0 +1,218 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceAuthMethodsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the auth method.", + }, + "is_primary": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether this auth method is the primary auth method for it's scope.\nTo change this value update the primary_auth_method_id field on the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this auth method is a part.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The auth method type.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.\nVersion is not required when you create an auth method.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to recursively list auth methods in the provided scope's child scopes.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + Description: "The scope ID in which to list auth methods.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceAuthMethods() *schema.Resource { + return &schema.Resource{ + Description: "Lists auth-methods", + ReadContext: dataSourceAuthMethodsRead, + Schema: dataSourceAuthMethodsSchema, + } +} + +func dataSourceAuthMethodsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "auth-methods", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceAuthMethodsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-auth-methods") + + return nil +} diff --git a/internal/provider/data_source_auth_methods_test.go b/internal/provider/data_source_auth_methods_test.go new file mode 100644 index 00000000..63d6f7e0 --- /dev/null +++ b/internal/provider/data_source_auth_methods_test.go @@ -0,0 +1,66 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + fooAuthMethodsDataMissingScope = ` +data "boundary_auth_methods" "foo" {} +` + fooAuthMethodsData = ` +data "boundary_auth_methods" "foo" { + depends_on = [boundary_auth_method.foo] + scope_id = boundary_scope.org1.id +} +` +) + +func TestAccDataSourceAuthMethods(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, fooAuthMethodsDataMissingScope), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, fooBaseAuthMethod, fooAuthMethodsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.%", "11"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.authorized_actions.#", "5"), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.description", "test auth method"), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.is_primary", "false"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.0.description", ""), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.0.parent_scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.scope.0.type", "org"), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "items.0.scope_id"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.type", "password"), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_auth_methods.foo", "items.0.version", "1"), + resource.TestCheckResourceAttrSet("data.boundary_auth_methods.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_auth_tokens.go b/internal/provider/data_source_auth_tokens.go new file mode 100644 index 00000000..b3c59a3d --- /dev/null +++ b/internal/provider/data_source_auth_tokens.go @@ -0,0 +1,220 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceAuthTokensSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Account associated with this Auth Token.", + }, + "approximate_last_used_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The approximate time this Auth Token was last used.", + }, + "auth_method_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Auth Method associated with this Auth Token.", + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "expiration_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this Auth Token expires.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Auth Token.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Scope in which this Auth Token was generated.", + }, + "token": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The token value, which will only be populated after authentication and is only ever visible to the end user whose login request resulted in this Auth Token being created.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the User associated with this Auth Token.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceAuthTokens() *schema.Resource { + return &schema.Resource{ + Description: "Lists auth-tokens", + ReadContext: dataSourceAuthTokensRead, + Schema: dataSourceAuthTokensSchema, + } +} + +func dataSourceAuthTokensRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "auth-tokens", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceAuthTokensSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-auth-tokens") + + return nil +} diff --git a/internal/provider/data_source_auth_tokens_test.go b/internal/provider/data_source_auth_tokens_test.go new file mode 100644 index 00000000..756a5a23 --- /dev/null +++ b/internal/provider/data_source_auth_tokens_test.go @@ -0,0 +1,53 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var fooAuthTokensDataMissingScopeId = ` +data "boundary_auth_tokens" "foo" {} +` + +var fooAuthTokensData = ` +data "boundary_auth_tokens" "foo" { + scope_id = "global" +} +` + +func TestAccDataAuthTokens(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, fooAuthTokensDataMissingScopeId), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooAuthTokensData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_auth_tokens.foo", "scope_id"), + resource.TestCheckResourceAttrSet("data.boundary_auth_tokens.foo", "items.0.account_id"), + resource.TestCheckResourceAttrSet("data.boundary_auth_tokens.foo", "items.0.auth_method_id"), + resource.TestCheckResourceAttr("data.boundary_auth_tokens.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttrSet("data.boundary_auth_tokens.foo", "items.0.scope.0.description"), + resource.TestCheckResourceAttrSet("data.boundary_auth_tokens.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_auth_tokens.foo", "items.0.scope.0.name", "global"), + resource.TestCheckResourceAttr("data.boundary_auth_tokens.foo", "items.0.scope.0.parent_scope_id", ""), + resource.TestCheckResourceAttr("data.boundary_auth_tokens.foo", "items.0.scope.0.type", "global"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_credential_libraries.go b/internal/provider/data_source_credential_libraries.go new file mode 100644 index 00000000..3a62a7f6 --- /dev/null +++ b/internal/provider/data_source_credential_libraries.go @@ -0,0 +1,207 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceCredentialLibrariesSchema = map[string]*schema.Schema{ + "credential_store_id": { + Type: schema.TypeString, + Optional: true, + }, + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "credential_store_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential Store of which this Credential Library is a part.", + }, + "credential_type": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Credential Library.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential Library type.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceCredentialLibraries() *schema.Resource { + return &schema.Resource{ + Description: "Lists credential-libraries", + ReadContext: dataSourceCredentialLibrariesRead, + Schema: dataSourceCredentialLibrariesSchema, + } +} + +func dataSourceCredentialLibrariesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "credential-libraries", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + if d.Get("credential_store_id") != "" { + q.Add("credential_store_id", d.Get("credential_store_id").(string)) + } + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("credential_store_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceCredentialLibrariesSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-credential-libraries") + + return nil +} diff --git a/internal/provider/data_source_credential_libraries_test.go b/internal/provider/data_source_credential_libraries_test.go new file mode 100644 index 00000000..3fb3d197 --- /dev/null +++ b/internal/provider/data_source_credential_libraries_test.go @@ -0,0 +1,76 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/boundary/testing/controller" + "github.com/hashicorp/boundary/testing/vault" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var ( + fooCredentialLibrariesDataMissingCredentialStoreId = ` +data "boundary_credential_libraries" "foo" {} +` + fooCredentialLibrariesData = ` +data "boundary_credential_libraries" "foo" { + depends_on = [boundary_credential_library_vault.example] + credential_store_id = boundary_credential_library_vault.example.credential_store_id +} +` +) + +func TestAccDataSourceCredentialLibraries(t *testing.T) { + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + + vc := vault.NewTestVaultServer(t) + _, token := vc.CreateToken(t) + credStoreRes := vaultCredStoreResource(vc, + vaultCredStoreName, + vaultCredStoreDesc, + vaultCredStoreNamespace, + "www.original.com", + token, + true) + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooCredentialLibrariesDataMissingCredentialStoreId), + ExpectError: regexp.MustCompile("This field must be a valid credential store id."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultCredLibResource, fooCredentialLibrariesData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "credential_store_id"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.%", "11"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.authorized_actions.#", "4"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.created_time"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.credential_store_id"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.description", "the foo"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.name", "foo"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.type", "vault-generic"), + resource.TestCheckResourceAttrSet("data.boundary_credential_libraries.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_credential_libraries.foo", "items.0.version", "1"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_credential_stores.go b/internal/provider/data_source_credential_stores.go new file mode 100644 index 00000000..afab1d41 --- /dev/null +++ b/internal/provider/data_source_credential_stores.go @@ -0,0 +1,211 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceCredentialStoresSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Credential Store.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this Credential Store is a part.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential Store type.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceCredentialStores() *schema.Resource { + return &schema.Resource{ + Description: "Lists credential-stores", + ReadContext: dataSourceCredentialStoresRead, + Schema: dataSourceCredentialStoresSchema, + } +} + +func dataSourceCredentialStoresRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "credential-stores", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceCredentialStoresSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-credential-stores") + + return nil +} diff --git a/internal/provider/data_source_credential_stores_test.go b/internal/provider/data_source_credential_stores_test.go new file mode 100644 index 00000000..1699f87f --- /dev/null +++ b/internal/provider/data_source_credential_stores_test.go @@ -0,0 +1,76 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/boundary/testing/controller" + "github.com/hashicorp/boundary/testing/vault" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var ( + fooCredentialStoresDataMissingScopeId = ` +data "boundary_credential_stores" "foo" {} +` + fooCredentialStoresData = ` +data "boundary_credential_stores" "foo" { + depends_on = [boundary_credential_store_vault.example] + scope_id = boundary_credential_store_vault.example.scope_id +} +` +) + +func TestAccDataSourceCredentialStores(t *testing.T) { + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + + vc := vault.NewTestVaultServer(t) + _, token := vc.CreateToken(t) + res := vaultCredStoreResource(vc, + vaultCredStoreName, + vaultCredStoreDesc, + vaultCredStoreNamespace, + "www.original.com", + token, + true) + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooCredentialStoresDataMissingScopeId), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, res, fooCredentialStoresData), + + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.%", "10"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.description", "the foo"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.name", "foo"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.scope_id"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.type", "vault"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_credential_stores.foo", "items.0.version", "1"), + resource.TestCheckResourceAttrSet("data.boundary_credential_stores.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_credentials.go b/internal/provider/data_source_credentials.go new file mode 100644 index 00000000..2fb69a40 --- /dev/null +++ b/internal/provider/data_source_credentials.go @@ -0,0 +1,203 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceCredentialsSchema = map[string]*schema.Schema{ + "credential_store_id": { + Type: schema.TypeString, + Optional: true, + }, + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "credential_store_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential Store of which this Credential is a part.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Credential.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential type.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceCredentials() *schema.Resource { + return &schema.Resource{ + Description: "Lists credentials", + ReadContext: dataSourceCredentialsRead, + Schema: dataSourceCredentialsSchema, + } +} + +func dataSourceCredentialsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "credentials", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + if d.Get("credential_store_id") != "" { + q.Add("credential_store_id", d.Get("credential_store_id").(string)) + } + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("credential_store_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceCredentialsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-credentials") + + return nil +} diff --git a/internal/provider/data_source_groups.go b/internal/provider/data_source_groups.go new file mode 100644 index 00000000..c2d9cd2d --- /dev/null +++ b/internal/provider/data_source_groups.go @@ -0,0 +1,232 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceGroupsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set descripton for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Group.", + }, + "member_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. Contains the list of member IDs in this Group.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "members": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The members of this Group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the member.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Scope ID of the member.", + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope of which this Group is a part.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceGroups() *schema.Resource { + return &schema.Resource{ + Description: "Lists groups", + ReadContext: dataSourceGroupsRead, + Schema: dataSourceGroupsSchema, + } +} + +func dataSourceGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "groups", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceGroupsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-groups") + + return nil +} diff --git a/internal/provider/data_source_groups_test.go b/internal/provider/data_source_groups_test.go new file mode 100644 index 00000000..bf37bddc --- /dev/null +++ b/internal/provider/data_source_groups_test.go @@ -0,0 +1,66 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + fooGroupsDataMissingScopeId = ` +data "boundary_groups" "foo" {} +` + fooGroupsData = ` +data "boundary_groups" "foo" { + depends_on = [boundary_group.with_members] + scope_id = boundary_group.with_members.scope_id +} +` +) + +func TestAccDataSourceGroups(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, fooGroupsDataMissingScopeId), + ExpectError: regexp.MustCompile("Incorrectly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, orgGroupWithMembers, fooGroupsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.%", "11"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.authorized_actions.#", "7"), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.description", "with members"), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.member_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.members.#", "0"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.name", ""), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.0.description", ""), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.0.parent_scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.scope.0.type", "org"), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "items.0.scope_id"), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_groups.foo", "items.0.version", "2"), + resource.TestCheckResourceAttrSet("data.boundary_groups.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_host_catalogs.go b/internal/provider/data_source_host_catalogs.go new file mode 100644 index 00000000..2019437f --- /dev/null +++ b/internal/provider/data_source_host_catalogs.go @@ -0,0 +1,243 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceHostCatalogsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the host.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "plugin": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the plugin in boundary, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Plugin.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the plugin resource in boundary, if any.", + }, + }, + }, + }, + "plugin_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the plugin of which this catalog is created.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this Host Catalog is a part.", + }, + "secrets_hmac": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The HMAC of the last secrets supplied via the API, if any.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Host Catalog.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceHostCatalogs() *schema.Resource { + return &schema.Resource{ + Description: "Lists host-catalogs", + ReadContext: dataSourceHostCatalogsRead, + Schema: dataSourceHostCatalogsSchema, + } +} + +func dataSourceHostCatalogsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "host-catalogs", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceHostCatalogsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-host-catalogs") + + return nil +} diff --git a/internal/provider/data_source_host_catalogs_test.go b/internal/provider/data_source_host_catalogs_test.go new file mode 100644 index 00000000..2bed7714 --- /dev/null +++ b/internal/provider/data_source_host_catalogs_test.go @@ -0,0 +1,69 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "fmt" + "regexp" + "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" +) + +var ( + fooHostCatalogsDataMissingSopeId = ` +data "boundary_host_catalogs" "foo" {} +` + fooHostCatalogsData = ` +data "boundary_host_catalogs" "foo" { + depends_on = [boundary_host_catalog.foo] + scope_id = boundary_host_catalog.foo.scope_id +} +` +) + +func TestAccDataSourceHostCatalogs(t *testing.T) { + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + + resName := "boundary_host_catalog" + typeStr := `type = "static"` + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooHostCatalogsDataMissingSopeId), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, fmt.Sprintf(projHostCatalog, resName, typeStr), fooHostCatalogsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.%", "13"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.authorized_actions.#", "4"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.description", "bar"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.name", "foo"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.scope_id"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.type", "static"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_host_catalogs.foo", "items.0.version", "1"), + resource.TestCheckResourceAttrSet("data.boundary_host_catalogs.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_host_sets.go b/internal/provider/data_source_host_sets.go new file mode 100644 index 00000000..7cea75e5 --- /dev/null +++ b/internal/provider/data_source_host_sets.go @@ -0,0 +1,246 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceHostSetsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "host_catalog_id": { + Type: schema.TypeString, + Optional: true, + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "host_catalog_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Host Catalog of which this Host Set is a part.", + }, + "host_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. A list of Hosts in this Host Set.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Host Set.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "plugin": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the plugin in boundary, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Plugin.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the plugin resource in boundary, if any.", + }, + }, + }, + }, + "preferred_endpoints": { + Type: schema.TypeList, + Computed: true, + Description: "multiple possible endpoints for a host. Preferences are specified by\n\"cidr:\" or \"dns:\", specifying which IP\naddress or DNS name out of a host's available possibilities should be\npreferred. If no preferences are specified, a value will be chosen from\namong all avialable values using a built-in priority order. May not be\nvalid for all plugin types.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "sync_interval_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: "An interger number of seconds indicating the amount of time that should\nelapse between syncs of the host set. The interval will be applied to the\nend of the previous sync operation, not the start. Setting to -1 will\ndisable syncing for that host set; setting to zero will cause the set to\nuse Boundary's default. The default may change between releases. May not\nbe valid for all plugin types.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the Host Set.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceHostSets() *schema.Resource { + return &schema.Resource{ + Description: "Lists host-sets", + ReadContext: dataSourceHostSetsRead, + Schema: dataSourceHostSetsSchema, + } +} + +func dataSourceHostSetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "host-sets", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + if d.Get("host_catalog_id") != "" { + q.Add("host_catalog_id", d.Get("host_catalog_id").(string)) + } + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("host_catalog_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceHostSetsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-host-sets") + + return nil +} diff --git a/internal/provider/data_source_host_sets_test.go b/internal/provider/data_source_host_sets_test.go new file mode 100644 index 00000000..f7970585 --- /dev/null +++ b/internal/provider/data_source_host_sets_test.go @@ -0,0 +1,95 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + testHostSet = ` +resource "boundary_host_catalog" "foo" { + depends_on = [boundary_role.proj1_admin] + type = "static" + name = "foo" + description = "bar" + scope_id = boundary_scope.proj1.id +} + +resource "boundary_host" "foo" { + depends_on = [boundary_host_catalog.foo] + type = "static" + host_catalog_id = boundary_host_catalog.foo.id + name = "host_1" + description = "My first host!" + address = "10.0.0.1" +} + +resource "boundary_host_set" "foo" { + host_catalog_id = boundary_host_catalog.foo.id + type = "static" + host_ids = [ + boundary_host.foo.id, + ] + name = "test" + description = "test hostset" +} +` + + fooHostSetsDataMissingHostCatalogId = ` +data "boundary_host_sets" "foo" {} +` + fooHostSetsData = ` +data "boundary_host_sets" "foo" { + depends_on = [boundary_host_set.foo] + host_catalog_id = boundary_host_set.foo.host_catalog_id +} +` +) + +func TestAccDataSourceHostSets(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, fooHostSetsDataMissingHostCatalogId), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, testHostSet, fooHostSetsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "host_catalog_id"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.%", "14"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.authorized_actions.#", "7"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.description", "test hostset"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.host_catalog_id"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.host_ids.#", "0"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.type", "static"), + resource.TestCheckResourceAttrSet("data.boundary_host_sets.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_host_sets.foo", "items.0.version", "2"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_hosts.go b/internal/provider/data_source_hosts.go new file mode 100644 index 00000000..687d888b --- /dev/null +++ b/internal/provider/data_source_hosts.go @@ -0,0 +1,259 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceHostsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "host_catalog_id": { + Type: schema.TypeString, + Optional: true, + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "dns_names": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The list of dns addresses associated with this host.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "external_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The external ID of the host, if any.", + }, + "external_name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. Refers to the name for a given host provided by the plugin enabled backing service.", + }, + "host_catalog_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Host Catalog of which this Host is a part.", + }, + "host_set_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. A list of Host Sets containing this Host.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Host.", + }, + "ip_addresses": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The list of ip addresses associated with this host.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "plugin": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the plugin in boundary, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Plugin.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the plugin resource in boundary, if any.", + }, + }, + }, + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the resource.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceHosts() *schema.Resource { + return &schema.Resource{ + Description: "Lists hosts", + ReadContext: dataSourceHostsRead, + Schema: dataSourceHostsSchema, + } +} + +func dataSourceHostsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "hosts", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + if d.Get("host_catalog_id") != "" { + q.Add("host_catalog_id", d.Get("host_catalog_id").(string)) + } + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("host_catalog_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceHostsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-hosts") + + return nil +} diff --git a/internal/provider/data_source_hosts_test.go b/internal/provider/data_source_hosts_test.go new file mode 100644 index 00000000..6a8d5f3b --- /dev/null +++ b/internal/provider/data_source_hosts_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + testHost = ` +resource "boundary_host_catalog" "foo" { + depends_on = [boundary_role.proj1_admin] + type = "static" + name = "foo" + description = "bar" + scope_id = boundary_scope.proj1.id +} + +resource "boundary_host" "foo" { + depends_on = [boundary_host_catalog.foo] + type = "static" + host_catalog_id = boundary_host_catalog.foo.id + name = "host_1" + description = "My first host!" + address = "10.0.0.1" +} +` + + fooHostsDataMissingHostCatalogId = ` +data "boundary_hosts" "foo" {} +` + fooHostsData = ` +data "boundary_hosts" "foo" { + depends_on = [boundary_host.foo] + host_catalog_id = boundary_host.foo.host_catalog_id +} +` +) + +func TestAccDataSourceHosts(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, fooHostsDataMissingHostCatalogId), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, testHost, fooHostsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "host_catalog_id"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.%", "16"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.description", "My first host!"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.host_catalog_id"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.host_set_ids.#", "0"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.name", "host_1"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.type", "static"), + resource.TestCheckResourceAttrSet("data.boundary_hosts.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_hosts.foo", "items.0.version", "1"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_managed_groups.go b/internal/provider/data_source_managed_groups.go new file mode 100644 index 00000000..a4691d27 --- /dev/null +++ b/internal/provider/data_source_managed_groups.go @@ -0,0 +1,210 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceManagedGroupsSchema = map[string]*schema.Schema{ + "auth_method_id": { + Type: schema.TypeString, + Optional: true, + }, + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_method_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Auth Method that is associated with this ManagedGroup.", + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the ManagedGroup.", + }, + "member_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs of the current set of members (accounts) that are associated with this ManagedGroup.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of this ManagedGroup.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceManagedGroups() *schema.Resource { + return &schema.Resource{ + Description: "Lists managed-groups", + ReadContext: dataSourceManagedGroupsRead, + Schema: dataSourceManagedGroupsSchema, + } +} + +func dataSourceManagedGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "managed-groups", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + if d.Get("auth_method_id") != "" { + q.Add("auth_method_id", d.Get("auth_method_id").(string)) + } + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("auth_method_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceManagedGroupsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-managed-groups") + + return nil +} diff --git a/internal/provider/data_source_managed_groups_test.go b/internal/provider/data_source_managed_groups_test.go new file mode 100644 index 00000000..7dbc92e2 --- /dev/null +++ b/internal/provider/data_source_managed_groups_test.go @@ -0,0 +1,55 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "fmt" + "regexp" + "strings" + "testing" + + "github.com/hashicorp/boundary/testing/controller" + "github.com/hashicorp/cap/oidc" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var ( + fooManagedGroupsDataMissingAuthMethodId = ` +data "boundary_managed_groups" "foo" {} +` + fooManagedGroupsData = ` +data "boundary_managed_groups" "foo" { + depends_on = [boundary_auth_method_oidc.foo] + auth_method_id = boundary_auth_method_oidc.foo.id +} +` +) + +func TestAccDataSourceManagedGroups(t *testing.T) { + tp := oidc.StartTestProvider(t) + defer tp.Stop() + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + + tpCert := strings.TrimSpace(tp.CACert()) + createConfig := fmt.Sprintf(fooAuthMethodOidc, fooAuthMethodOidcDesc, tp.Addr(), tpCert) + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooManagedGroupsDataMissingAuthMethodId), + ExpectError: regexp.MustCompile("Invalid formatted identifier."), + }, + { + Config: testConfig(url, fooOrg, createConfig, fooManagedGroupsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.boundary_managed_groups.foo", "auth_method_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_policies.go b/internal/provider/data_source_policies.go new file mode 100644 index 00000000..ac1f5907 --- /dev/null +++ b/internal/provider/data_source_policies.go @@ -0,0 +1,209 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourcePoliciesSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The id of the storage policy.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The scope id of this policy. This must be defined for policy creation, but\nis otherwise output only.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The policy's type.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure\nthis resource has not changed. The mutation will fail if the version does\nnot match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourcePolicies() *schema.Resource { + return &schema.Resource{ + Description: "Lists policies", + ReadContext: dataSourcePoliciesRead, + Schema: dataSourcePoliciesSchema, + } +} + +func dataSourcePoliciesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "policies", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourcePoliciesSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-policies") + + return nil +} diff --git a/internal/provider/data_source_roles.go b/internal/provider/data_source_roles.go new file mode 100644 index 00000000..858c5aa2 --- /dev/null +++ b/internal/provider/data_source_roles.go @@ -0,0 +1,311 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceRolesSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "grant_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Scope the grants will apply to. If the Role is at the global scope,\nthis can be an org or project. If the Role is at an org scope, this can be\na project within the org. It is invalid for this to be anything other than\nthe Role's scope when the Role's scope is a project.\n\nDeprecated: Use \"grant_scope_ids\" instead.", + }, + "grant_scope_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs of Scopes the grants will apply to. This can include\nthe role's own scope ID, or \"this\" for the same behavior; specific IDs of\nscopes that are children of the role's scope; the value \"children\" to match\nall direct child scopes of the role's scope; or the value \"descendants\" to\nmatch all descendant scopes (e.g. child scopes, children of child scopes;\nonly valid at \"global\" scope since it is the only one with children of\nchildren).", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "grant_strings": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The grants that this role provides for its principals.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "grants": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The parsed grant information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "canonical": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The canonically-formatted string.", + }, + "json": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The actions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID, if set.\nDeprecated: use \"ids\" instead.", + }, + "ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs, if set.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type, if set.", + }, + }, + }, + }, + "raw": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The original user-supplied string.", + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Role.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "principal_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs (only) of principals that are assigned to this role.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "principals": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The principals that are assigned to this role.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the principal.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Scope of the principal.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the principal.", + }, + }, + }, + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope containing this Role.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceRoles() *schema.Resource { + return &schema.Resource{ + Description: "Lists roles", + ReadContext: dataSourceRolesRead, + Schema: dataSourceRolesSchema, + } +} + +func dataSourceRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "roles", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceRolesSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-roles") + + return nil +} diff --git a/internal/provider/data_source_roles_test.go b/internal/provider/data_source_roles_test.go new file mode 100644 index 00000000..16e6ebf2 --- /dev/null +++ b/internal/provider/data_source_roles_test.go @@ -0,0 +1,69 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + fooRolesDataMissingScope = ` +data "boundary_roles" "foo" {} +` + + fooRolesData = ` +data "boundary_roles" "foo" { + depends_on = [boundary_role.foo] + scope_id = boundary_role.foo.scope_id +} +` +) + +func TestAccDataSourceRoles(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, fooRolesDataMissingScope), + ExpectError: regexp.MustCompile("Improperly formatted field."), + }, + { + Config: testConfig(url, fooOrg, orgRole, fooRolesData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.%", "15"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.authorized_actions.#", "13"), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.description", "bar"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.grant_strings.#", "0"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.grants.#", "0"), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.principal_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.principals.#", "0"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.0.description", ""), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.0.parent_scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.scope.0.type", "org"), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "items.0.scope_id"), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_roles.foo", "items.0.version", "2"), + resource.TestCheckResourceAttrSet("data.boundary_roles.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_scopes.go b/internal/provider/data_source_scopes.go new file mode 100644 index 00000000..938314a2 --- /dev/null +++ b/internal/provider/data_source_scopes.go @@ -0,0 +1,220 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceScopesSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set descripton for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "primary_auth_method_id": { + Type: schema.TypeString, + Computed: true, + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope this resource is in. If this is the \"global\" scope this field will be empty.", + }, + "storage_policy_id": { + Type: schema.TypeString, + Computed: true, + Description: "The attached storage policy id.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the resource.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token used to continue an existing iteration or\nrequest updated items. If paginating, use this token in the\nnext list request.", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of an pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceScopes() *schema.Resource { + return &schema.Resource{ + Description: "Lists scopes", + ReadContext: dataSourceScopesRead, + Schema: dataSourceScopesSchema, + } +} + +func dataSourceScopesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "scopes", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceScopesSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-scopes") + + return nil +} diff --git a/internal/provider/data_source_scopes_test.go b/internal/provider/data_source_scopes_test.go new file mode 100644 index 00000000..fdd7d36d --- /dev/null +++ b/internal/provider/data_source_scopes_test.go @@ -0,0 +1,52 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "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" +) + +var fooScopesData = ` +data "boundary_scopes" "foo" {} +` + +func TestAccDataSourceScopes(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, fooScopesData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.%", "12"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.authorized_actions.#", "6"), + resource.TestCheckResourceAttrSet("data.boundary_scopes.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.description", "Provides an initial org scope in Boundary"), + resource.TestCheckResourceAttrSet("data.boundary_scopes.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.name", "Generated org scope"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.primary_auth_method_id", ""), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.description", "Global Scope"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.id", "global"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.name", "global"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.parent_scope_id", ""), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope.0.type", "global"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.type", "org"), + resource.TestCheckResourceAttrSet("data.boundary_scopes.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_scopes.foo", "items.0.version", "1"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_session_recordings.go b/internal/provider/data_source_session_recordings.go new file mode 100644 index 00000000..f94f80d6 --- /dev/null +++ b/internal/provider/data_source_session_recordings.go @@ -0,0 +1,761 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceSessionRecordingsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Description: "The items returned in this page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "bytes_down": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes downloaded to the client in the Session.\nThis includes all bytes downloaded over all Connections, including\nany protocol overhead.", + }, + "bytes_up": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes uploaded from the client in the Session.\nThis includes all bytes uploaded over all Connections, including\nany protocol overhead.", + }, + "connection_recordings": { + Type: schema.TypeList, + Computed: true, + Description: "The recordings of the connections that were created in the Session.\nThis field may be unset when listing Session recordings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bytes_down": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes downloaded to the client in the Connection.\nThis includes any protocol overhead.", + }, + "bytes_up": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes uploaded from the client in the Connection.\nThis includes any protocol overhead.", + }, + "channel_recordings": { + Type: schema.TypeList, + Computed: true, + Description: "Optionally, the channels used in this Connection,\nif it is using a multiplexed protocol, such as SSH.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bytes_down": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes downloaded to the client in the Channel.", + }, + "bytes_up": { + Type: schema.TypeString, + Computed: true, + Description: "The total number of bytes uploaded from the client in the Channel.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Channel was created in the controller.", + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: "The total duration of the Channel.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Channel ended.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Channel recording.", + }, + "mime_types": { + Type: schema.TypeList, + Computed: true, + Description: "MimeTypes define the mime types that can\nbe used to consume the recording of this Channel.\nThe only supported mime type is \"application/x-asciicast\".", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Channel started.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time of the most recent update to the Channel.", + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Connection was created in the controller.", + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: "The total duration of the Connection.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Connection ended.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Connection recording.", + }, + "mime_types": { + Type: schema.TypeList, + Computed: true, + Description: "MimeTypes define the mime types that can\nbe used to consume the recording of this Connection.\nNo mime types are currently supported.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Connection started.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time of the most recent update to the Connection.", + }, + }, + }, + }, + "create_time_values": { + Type: schema.TypeList, + Computed: true, + Description: "ValuesAtTime contain information about other Boundary resources as they\nwere at a certain time through the lifetime of the Session Recording.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_libraries": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the Credential Libraries used for this session.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_store": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description for identification purposes if set.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential Store.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name for identification purposes if set.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this Credential Store is a part.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential Store type.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description of this Credential Library.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential Library.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name of this Credential Library.", + }, + "purposes": { + Type: schema.TypeList, + Computed: true, + Description: "The purposes for which this CredentialLibrary was attached to the sesssion.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential Library type.", + }, + }, + }, + }, + "credentials": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the Credentials used for this session.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_store": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description for identification purposes if set.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential Store.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name for identification purposes if set.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this Credential Store is a part.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential Store type.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the credential.", + }, + "purposes": { + Type: schema.TypeList, + Computed: true, + Description: "The purposes for which this Credential was attached to the sesssion.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The Credential type.", + }, + }, + }, + }, + "host": { + Type: schema.TypeList, + Computed: true, + Description: "Host describes the Host that was chosen for the recorded session.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the Host, if set.", + }, + "external_id": { + Type: schema.TypeString, + Computed: true, + Description: "The external id of the Host, if any.", + }, + "external_name": { + Type: schema.TypeString, + Computed: true, + Description: "The external name of the Host, if any.", + }, + "host_catalog": { + Type: schema.TypeList, + Computed: true, + Description: "HostCatalog describes the HostCatalog that contains the host chosen for the\nrecorded session.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the Host Catalog.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "plugin_id": { + Type: schema.TypeString, + Computed: true, + Description: "The plugin id used by this Host Catalog, if any.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the Host, if set.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "target": { + Type: schema.TypeList, + Computed: true, + Description: "Target describes a target in Boundary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the Target, if set.", + }, + "egress_worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expressions to filter the egress workers that are allowed to satisfy this request.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Target.", + }, + "ingress_worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expressions to filter the ingress workers that are allowed to satisfy this request.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the Target, if set.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "session_connection_limit": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum number of connections allowed in a Session. Unlimited is indicated by the value -1.", + }, + "session_max_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum total lifetime of a created Session, in seconds.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the Target.", + }, + "worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expression to filter the workers that are allowed to satisfy this request.", + }, + }, + }, + }, + "user": { + Type: schema.TypeList, + Computed: true, + Description: "User describes an authenticated user in Boundary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the User that created the Session.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the User.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the User that created the Session.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Session Recording was created in the controller.", + }, + "delete_after": { + Type: schema.TypeString, + Computed: true, + Description: "The time a session recording is scheduled to be automatically deleted.", + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: "The total duration of the Session.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Session ended.", + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint of the Session; that is, the address to which the egress worker connected.", + }, + "error_details": { + Type: schema.TypeString, + Computed: true, + Description: "Any error seen during the closing of the session recording.\nCurrently only set if state is \"unknown\".", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Session recording.", + }, + "mime_types": { + Type: schema.TypeList, + Computed: true, + Description: "MimeTypes define the mime types that can\nbe used to consume the recording of this Session.\nNo mime types are currently supported.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "retain_until": { + Type: schema.TypeString, + Computed: true, + Description: "The time until a session recording is required to be stored.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "session_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Session which this Session Recording recorded.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time the Session started.", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "The current state of the session recording. One of\n\"started\", \"available\" and \"unknown\".", + }, + "storage_bucket_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Storage Bucket for the Target of this Session Recording.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the Session that was recorded (e.g. ssh).", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The time of the most recent update to the Session Recording.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to recurse into child scopes when listing.\nIf set and scope_id is empty, shows session recordings in\nall scopes the caller has access to.", + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + Description: "The scope in which to list session recordings.\nMust be set unless recursive is set.", + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceSessionRecordings() *schema.Resource { + return &schema.Resource{ + Description: "Lists session-recordings", + ReadContext: dataSourceSessionRecordingsRead, + Schema: dataSourceSessionRecordingsSchema, + } +} + +func dataSourceSessionRecordingsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "session-recordings", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + q.Add("scope_id", d.Get("scope_id").(string)) + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceSessionRecordingsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-session-recordings") + + return nil +} diff --git a/internal/provider/data_source_sessions.go b/internal/provider/data_source_sessions.go new file mode 100644 index 00000000..14753080 --- /dev/null +++ b/internal/provider/data_source_sessions.go @@ -0,0 +1,320 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceSessionsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "include_terminated": { + Type: schema.TypeBool, + Optional: true, + Description: "Experimental. By default only non-terminated (i.e. pending, active, canceling) are returned.\nSet this option to include terminated sessions as well.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_token_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Auth Token used to authenticate.", + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "certificate": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The certificate generated for the session. Raw DER bytes.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The associated connections with this session.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bytes_down": { + Type: schema.TypeString, + Computed: true, + }, + "bytes_up": { + Type: schema.TypeString, + Computed: true, + }, + "client_tcp_address": { + Type: schema.TypeString, + Computed: true, + }, + "client_tcp_port": { + Type: schema.TypeInt, + Computed: true, + }, + "closed_reason": { + Type: schema.TypeString, + Computed: true, + }, + "endpoint_tcp_address": { + Type: schema.TypeString, + Computed: true, + }, + "endpoint_tcp_port": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The endpoint of the Session; that is, the address to which the worker is proxying data.", + }, + "expiration_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. After this time the connection will be expired, e.g. forcefully terminated.", + }, + "host_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Host used by the Session.", + }, + "host_set_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Host Set sourcing the Host for this Session.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Session.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Scope of the Session.", + }, + "states": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The states of this Session in descending order from the current state to the first.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time the Session stopped being in this state.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time the Session entered this state.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the Session, e.g. \"pending\", \"active\", \"canceling\", \"terminated\".", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The current status of this Session.", + }, + "target_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Target that created this Session.", + }, + "termination_reason": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. If the session is terminated, this provides a short description as to why.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. Type of the Session (e.g. tcp).", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the User that requested the Session.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used when canceling this Session to ensure that the operation is acting on a known session state.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceSessions() *schema.Resource { + return &schema.Resource{ + Description: "Lists sessions", + ReadContext: dataSourceSessionsRead, + Schema: dataSourceSessionsSchema, + } +} + +func dataSourceSessionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "sessions", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + include_terminated := d.Get("include_terminated").(bool) + if include_terminated { + q.Add("include_terminated", strconv.FormatBool(include_terminated)) + } + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceSessionsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-sessions") + + return nil +} diff --git a/internal/provider/data_source_sessions_test.go b/internal/provider/data_source_sessions_test.go new file mode 100644 index 00000000..6c7cb4ec --- /dev/null +++ b/internal/provider/data_source_sessions_test.go @@ -0,0 +1,33 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var fooSessionsData = ` +data "boundary_sessions" "foo" {} +` + +func TestAccDataSourceSessions(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, fooSessionsData), + ExpectError: regexp.MustCompile("Improperly formatted identifier."), + }, + }, + }) +} diff --git a/internal/provider/data_source_storage_buckets.go b/internal/provider/data_source_storage_buckets.go new file mode 100644 index 00000000..aabf9ebe --- /dev/null +++ b/internal/provider/data_source_storage_buckets.go @@ -0,0 +1,257 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceStorageBucketsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "bucket_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the bucket within the external object store service.", + }, + "bucket_prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The prefix used to organize the data held within the external object store.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the storage bucket.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "plugin": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the plugin in boundary, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Plugin.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the plugin resource in boundary, if any.", + }, + }, + }, + }, + "plugin_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the plugin of which this storage bucket is created.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope of which this storage bucket is a part.", + }, + "secrets_hmac": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The HMAC of the last secrets supplied via the API, if any.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Storage Bucket (currently only plugin).", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + "worker_filter": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf you do not set a page size, Boundary uses the configured default page size.\nIf the page_size is greater than the default page size configured,\nBoundary truncates the page size to this number.", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceStorageBuckets() *schema.Resource { + return &schema.Resource{ + Description: "Lists storage-buckets", + ReadContext: dataSourceStorageBucketsRead, + Schema: dataSourceStorageBucketsSchema, + } +} + +func dataSourceStorageBucketsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "storage-buckets", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceStorageBucketsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-storage-buckets") + + return nil +} diff --git a/internal/provider/data_source_targets.go b/internal/provider/data_source_targets.go new file mode 100644 index 00000000..625cbc42 --- /dev/null +++ b/internal/provider/data_source_targets.go @@ -0,0 +1,449 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceTargetsSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + Description: "You can specify that the filter should only return items that match.\nRefer to [filter expressions](https://developer.hashicorp.com/boundary/docs/concepts/filtering) for more information.", + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "Optional string value that represents a network resource and is used when establishing a session.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The aliases that point to this Target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorize_session_arguments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_id": { + Type: schema.TypeString, + Computed: true, + Description: "host_id is the id of the host that the session will be authorized for.\nWhen specified authorizing a session using this alias will have the same\neffect of authorizing a session to the alias' destination_id and passing\nin this value through the -host-id flag. If the host-id flag is also\nspecified when calling authorize-session an error will be returned unless\nthe provided host-id matches this value.", + }, + }, + }, + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the alias referencing this target.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Ouput only. The value of the alias referencing this target.", + }, + }, + }, + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "brokered_credential_source_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs of the brokered credential source ids associated with this Target.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "brokered_credential_sources": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The brokered credential sources associated with this Target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_store_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Credential Store to which this Credential source belongs.", + }, + "credential_type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the credential, empty if unspecified.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the Credential source.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential. May be empty if the credential is dynamically generated from a library.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the Credential source.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the credential source (e.g. \"vault\"; not the type of the credential itself).", + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "egress_worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expressions to filter the egress workers that are allowed to satisfy this request.", + }, + "host_source_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs of the Host Sources associated with this Target.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "host_sources": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The Host Sources associated with this Target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_catalog_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Host Catalog to which this Host Source belongs.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Host Set.", + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the resource.", + }, + "ingress_worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expressions to filter the ingress workers that are allowed to satisfy this request.\nUnsupported on OSS.", + }, + "injected_application_credential_source_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The IDs of the injected application credential source ids associated with this Target.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "injected_application_credential_sources": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The injected application credential sources associated with this Target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_store_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Credential Store to which this Credential source belongs.", + }, + "credential_type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the credential, empty if unspecified.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The description of the Credential source.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Credential. May be empty if the credential is dynamically generated from a library.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The name of the Credential source.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the credential source (e.g. \"vault\"; not the type of the credential itself).", + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Required name for identification purposes.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Scope of of this resource. This must be defined for creation of this resource, but is otherwise output only.", + }, + "session_connection_limit": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum number of connections allowed in a Session. Unlimited is indicated by the value -1.", + }, + "session_max_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum total lifetime of a created Session, in seconds.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the Target.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + "with_aliases": { + Type: schema.TypeList, + Computed: true, + Description: "Input only. with_aliases specify the aliases that should be created when\nthe target is created. This field is only usable at target creation time.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorize_session_arguments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_id": { + Type: schema.TypeString, + Computed: true, + Description: "host_id is the id of the host that the session will be authorized for.\nWhen specified authorizing a session using this alias will have the same\neffect of authorizing a session to the alias' destination_id and passing\nin this value through the -host-id flag. If the host-id flag is also\nspecified when calling authorize-session an error will be returned unless\nthe provided host-id matches this value.", + }, + }, + }, + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the alias referencing this target.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Ouput only. The value of the alias referencing this target.", + }, + }, + }, + }, + "worker_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Optional boolean expression to filter the workers that are allowed to satisfy this request.\nDeprecated; use egress or ingress worker filters instead.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceTargets() *schema.Resource { + return &schema.Resource{ + Description: "Lists targets", + ReadContext: dataSourceTargetsRead, + Schema: dataSourceTargetsSchema, + } +} + +func dataSourceTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "targets", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceTargetsSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-targets") + + return nil +} diff --git a/internal/provider/data_source_targets_test.go b/internal/provider/data_source_targets_test.go new file mode 100644 index 00000000..2f5d02df --- /dev/null +++ b/internal/provider/data_source_targets_test.go @@ -0,0 +1,88 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/boundary/testing/controller" + "github.com/hashicorp/boundary/testing/vault" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var ( + fooTargetsDataMissingScope = ` +data "boundary_targets" "foo" {} +` + fooTargetsData = ` +data "boundary_targets" "foo" { + depends_on = [boundary_target.foo] + scope_id = boundary_target.foo.scope_id +} +` +) + +func TestAccDataSourceTargets(t *testing.T) { + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + + vc := vault.NewTestVaultServer(t) + _, token := vc.CreateToken(t) + credStoreRes := vaultCredStoreResource(vc, + vaultCredStoreName, + vaultCredStoreDesc, + vaultCredStoreNamespace, + "www.original.com", + token, + true) + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooTargetsDataMissingScope), + ExpectError: regexp.MustCompile("scope_id: This field must be a valid project scope ID or the list operation.*\n.*must be recursive."), + }, + { + Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, fooBarCredLibs, fooBarHostSet, fooTarget, fooTargetsData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_targets.foo", "id", "boundary-targets"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.%", "24"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.application_credential_libraries.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.application_credential_library_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.application_credential_source_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.application_credential_sources.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.authorized_actions.#", "11"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.description", "bar"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.host_set_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.host_sets.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.host_source_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.host_sources.#", "0"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.scope.0.description", "foo"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.scope.0.name", "proj1"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.scope.0.parent_scope_id"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.scope.0.type", "project"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.scope_id"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.session_connection_limit", "6"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.session_max_seconds", "6000"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.type", "tcp"), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.version", "3"), + resource.TestCheckResourceAttr("data.boundary_targets.foo", "items.0.egress_worker_filter", "type == \"foo\""), + resource.TestCheckResourceAttrSet("data.boundary_targets.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_users.go b/internal/provider/data_source_users.go new file mode 100644 index 00000000..9ea23ca1 --- /dev/null +++ b/internal/provider/data_source_users.go @@ -0,0 +1,247 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceUsersSchema = map[string]*schema.Schema{ + "est_item_count": { + Type: schema.TypeInt, + Computed: true, + Description: "An estimate at the total items available. This may change during pagination.", + }, + "filter": { + Type: schema.TypeString, + Optional: true, + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_ids": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. Contains the list of Account IDs linked to this User.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "accounts": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The Accounts linked to this User.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the Account.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The Scope containing the Account.", + }, + }, + }, + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for this user.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes.", + }, + "email": { + Type: schema.TypeString, + Computed: true, + }, + "full_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the User.", + }, + "login_name": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes.", + }, + "primary_account_id": { + Type: schema.TypeString, + Computed: true, + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope this resource is in.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + }, + }, + }, + "list_token": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "An opaque token that Boundary uses to continue an existing iteration or\nrequest updated items. If you do not specify a token, pagination\nstarts from the beginning. To learn more about list pagination\nin Boundary, refer to [list pagination](https://developer.hashicorp.com/boundary/docs/api-clients/api/pagination).", + }, + "page_size": { + Type: schema.TypeInt, + Optional: true, + Description: "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nthe page size will be truncated to this number..", + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "removed_ids": { + Type: schema.TypeList, + Computed: true, + Description: "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page.", + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, + "sort_by": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the field which the items are sorted by.", + }, + "sort_dir": { + Type: schema.TypeString, + Computed: true, + Description: "The direction of the sort, either \"asc\" or \"desc\".", + }, +} + +func dataSourceUsers() *schema.Resource { + return &schema.Resource{ + Description: "Lists users", + ReadContext: dataSourceUsersRead, + Schema: dataSourceUsersSchema, + } +} + +func dataSourceUsersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "users", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + q.Add("list_token", d.Get("list_token").(string)) + if d.Get("scope_id") != 0 { + q.Add("page_size", strconv.Itoa(d.Get("page_size").(int))) + } + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceUsersSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-users") + + return nil +} diff --git a/internal/provider/data_source_users_test.go b/internal/provider/data_source_users_test.go new file mode 100644 index 00000000..45be032d --- /dev/null +++ b/internal/provider/data_source_users_test.go @@ -0,0 +1,71 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package provider + +import ( + "regexp" + "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" +) + +var ( + fooUsersDataMissingScope = ` +data "boundary_users" "foo" {} +` + fooUsersData = ` +data "boundary_users" "foo" { + depends_on = [boundary_user.org1] + scope_id = boundary_user.org1.scope_id +} +` +) + +func TestAccDataSourceUsers(t *testing.T) { + tc := controller.NewTestController(t, tcConfig...) + defer tc.Shutdown() + url := tc.ApiAddrs()[0] + token := tc.Token().Token + + var provider *schema.Provider + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories(&provider), + Steps: []resource.TestStep{ + { + Config: testConfig(url, fooUsersDataMissingScope), + ExpectError: regexp.MustCompile(""), + }, + { + Config: testConfigWithToken(url, token, fooOrg, orgUser, fooUsersData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.#", "1"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.%", "15"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.account_ids.#", "0"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.accounts.#", "0"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.authorized_actions.#", "8"), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "items.0.created_time"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.description", "bar"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.email", ""), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.full_name", ""), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "items.0.id"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.login_name", ""), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.name", "test"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.primary_account_id", ""), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.#", "1"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.0.%", "5"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.0.description", ""), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "items.0.scope.0.id"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.0.name", "org1"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.0.parent_scope_id", "global"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.scope.0.type", "org"), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "items.0.scope_id"), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "items.0.updated_time"), + resource.TestCheckResourceAttr("data.boundary_users.foo", "items.0.version", "1"), + resource.TestCheckResourceAttrSet("data.boundary_users.foo", "scope_id"), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_workers.go b/internal/provider/data_source_workers.go new file mode 100644 index 00000000..f62f6282 --- /dev/null +++ b/internal/provider/data_source_workers.go @@ -0,0 +1,207 @@ +// Code generated by "make datasources"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "net/url" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var dataSourceWorkersSchema = map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Optional: true, + }, + "items": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "active_connection_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Output only. The number of connections that this worker is currently handling.", + }, + "address": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The address that this worker is reachable at, as sourced from\nthe worker's configuration file.", + }, + "authorized_actions": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The available actions on this resource for the requester.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "controller_generated_activation_token": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. An activation token that can be given to a worker to correlate\nit to the created resource.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was created.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Optional user-set description for identification purposes. Can only be set\nthrough the API for `pki`-type workers; read-only for `kms`-type workers.", + }, + "directly_connected_downstream_workers": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. The ids of the workers directly connected to this worker.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The ID of the User.", + }, + "last_status_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this worker daemon last reported its status.", + }, + "local_storage_state": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name for identification purposes. Can only be set through the API\nfor `pki`-type workers; read-only for `kms`-type workers.", + }, + "release_version": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The version of the Boundary binary the worker is running.", + }, + "scope": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the scope, if any.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope, if any.", + }, + "parent_scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the parent scope, if any. This field is empty if it is the \"global\" scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the scope.", + }, + }, + }, + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Scope this resource is in.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The type of the worker, denoted by how it authenticates: `pki`\nor `kms`.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time this resource was last updated.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version.", + }, + "worker_generated_auth_token": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "recursive": { + Type: schema.TypeBool, + Optional: true, + }, + "scope_id": { + Type: schema.TypeString, + Optional: true, + }, +} + +func dataSourceWorkers() *schema.Resource { + return &schema.Resource{ + Description: "Lists workers", + ReadContext: dataSourceWorkersRead, + Schema: dataSourceWorkersSchema, + } +} + +func dataSourceWorkersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*metaData).client + + req, err := client.NewRequest(ctx, "GET", "workers", nil) + if err != nil { + return diag.FromErr(err) + } + + q := url.Values{} + q.Add("filter", d.Get("filter").(string)) + recursive := d.Get("recursive").(bool) + if recursive { + q.Add("recursive", strconv.FormatBool(recursive)) + } + if d.Get("scope_id") != "" { + q.Add("scope_id", d.Get("scope_id").(string)) + } + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + diag.FromErr(err) + } + apiError, err := resp.Decode(nil) + if err != nil { + return diag.FromErr(err) + } + if apiError != nil { + return apiErr(apiError) + } + err = set(dataSourceWorkersSchema, d, resp.Map) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("boundary-workers") + + return nil +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a36a0b74..9bfe7a6a 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -131,11 +131,26 @@ func New() *schema.Provider { "boundary_worker": resourceWorker(), }, DataSourcesMap: map[string]*schema.Resource{ - "boundary_account": dataSourceAccount(), - "boundary_auth_method": dataSourceAuthMethod(), - "boundary_group": dataSourceGroup(), - "boundary_scope": dataSourceScope(), - "boundary_user": dataSourceUser(), + "boundary_accounts": dataSourceAccounts(), + "boundary_auth_method": dataSourceAuthMethod(), + "boundary_auth_methods": dataSourceAuthMethods(), + "boundary_auth_tokens": dataSourceAuthTokens(), + "boundary_credential_libraries": dataSourceCredentialLibraries(), + "boundary_credential_stores": dataSourceCredentialStores(), + "boundary_group": dataSourceGroup(), + "boundary_groups": dataSourceGroups(), + "boundary_host_catalogs": dataSourceHostCatalogs(), + "boundary_host_sets": dataSourceHostSets(), + "boundary_hosts": dataSourceHosts(), + "boundary_managed_groups": dataSourceManagedGroups(), + "boundary_roles": dataSourceRoles(), + "boundary_scope": dataSourceScope(), + "boundary_scopes": dataSourceScopes(), + "boundary_sessions": dataSourceSessions(), + "boundary_targets": dataSourceTargets(), + "boundary_user": dataSourceUser(), + "boundary_users": dataSourceUsers(), + "boundary_account": dataSourceAccount(), }, }