Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f1cf40e9 | ||
|
|
4f4318d005 | ||
|
|
5af7f8b662 | ||
|
|
3d42195a26 | ||
|
|
9bc08d4c48 | ||
|
|
4de1075067 | ||
|
|
dc46913c63 | ||
|
|
bb85735e02 | ||
|
|
f49ee1d5bc | ||
|
|
b01f482fb2 | ||
|
|
b69e175687 |
No files matched your search
@@ -7,8 +7,8 @@ jobs:
|
||||
steps:
|
||||
- add_ssh_keys:
|
||||
fingerprints:
|
||||
# hashicorp-ci github "machine" user, for private modules
|
||||
- "c6:96:98:82:dc:04:6c:39:dd:ac:83:05:e3:15:1c:98"
|
||||
# hc-github-team-secure-boundary github user,TF_ACC=1 ~/.go/bin/go test ./... -v $(TESTARGS) -timeout 120m to read private modules
|
||||
- "d4:7f:b2:f7:6f:4d:e7:21:cc:d2:b7:6a:8b:68:e6:d4"
|
||||
- checkout
|
||||
- run:
|
||||
name: "Run Acceptance Tests"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.15.2
|
||||
1.16.3
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.0.2 (May 06, 2021)
|
||||
|
||||
* Adds OIDC account resource
|
||||
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/105))
|
||||
* Adds OIDC auth method resource
|
||||
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/105))
|
||||
* Deprecates fields on `resource_auth_method` that will be replaced in the future with generic `attributes` attribute.
|
||||
|
||||
## 1.0.1 (February 02, 2021)
|
||||
|
||||
### New and Improved
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Contributing to Boundary
|
||||
|
||||
Thank you for contributing to Boundary! Here you can find common questions around reporting issues and opening
|
||||
pull requests to our project.
|
||||
|
||||
When contributing in any way to the Boundary project (new issue, PR, etc), please be aware that our team identifies with many gender pronouns and to use non-binary pronouns when addressing our team. For more reading on our code of conduct, please see the [HashiCorp community guidelines](https://www.hashicorp.com/community-guidelines).
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.15
|
||||
FROM golang:1.16
|
||||
|
||||
WORKDIR /go/src/terraform-provider-boundary
|
||||
COPY . .
|
||||
|
||||
@@ -9,7 +9,7 @@ Requirements
|
||||
------------
|
||||
|
||||
- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x
|
||||
- [Go](https://golang.org/doc/install) >= 1.15
|
||||
- [Go](https://golang.org/doc/install) >= 1.16
|
||||
|
||||
Building The Provider
|
||||
---------------------
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
VERSION="1.15"
|
||||
VERSION="1.16"
|
||||
|
||||
[ -z "$GOROOT" ] && GOROOT="$HOME/.go"
|
||||
[ -z "$GOPATH" ] && GOPATH="$HOME/go"
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The account resource allows you to configure a Boundary account.
|
||||
---
|
||||
|
||||
# Resource `boundary_account`
|
||||
# boundary_account (Resource)
|
||||
|
||||
The account resource allows you to configure a Boundary account.
|
||||
|
||||
@@ -45,11 +45,11 @@ resource "boundary_account" "jeff" {
|
||||
### Optional
|
||||
|
||||
- **description** (String) The account description.
|
||||
- **login_name** (String) The login name for this account.
|
||||
- **login_name** (String, Deprecated) The login name for this account.
|
||||
- **name** (String) The account name. Defaults to the resource name.
|
||||
- **password** (String) The account password. Only set on create, changes will not be reflected when updating account.
|
||||
- **password** (String, Deprecated) The account password. Only set on create, changes will not be reflected when updating account.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the account.
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "boundary_account_oidc Resource - terraform-provider-boundary"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
The account resource allows you to configure a Boundary account.
|
||||
---
|
||||
|
||||
# boundary_account_oidc (Resource)
|
||||
|
||||
The account resource allows you to configure a Boundary account.
|
||||
|
||||
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- **auth_method_id** (String) The resource ID for the auth method.
|
||||
|
||||
### Optional
|
||||
|
||||
- **description** (String) The account description.
|
||||
- **issuer** (String) The OIDC issuer.
|
||||
- **name** (String) The account name. Defaults to the resource name.
|
||||
- **subject** (String) The OIDC subject.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the account.
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "boundary_account_password Resource - terraform-provider-boundary"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
The account resource allows you to configure a Boundary account.
|
||||
---
|
||||
|
||||
# boundary_account_password (Resource)
|
||||
|
||||
The account resource allows you to configure a Boundary account.
|
||||
|
||||
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- **auth_method_id** (String) The resource ID for the auth method.
|
||||
- **type** (String) The resource type.
|
||||
|
||||
### Optional
|
||||
|
||||
- **description** (String) The account description.
|
||||
- **login_name** (String, Deprecated) The login name for this account.
|
||||
- **name** (String) The account name. Defaults to the resource name.
|
||||
- **password** (String, Deprecated) The account password. Only set on create, changes will not be reflected when updating account.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the account.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The auth method resource allows you to configure a Boundary auth_method.
|
||||
---
|
||||
|
||||
# Resource `boundary_auth_method`
|
||||
# boundary_auth_method (Resource)
|
||||
|
||||
The auth method resource allows you to configure a Boundary auth_method.
|
||||
|
||||
@@ -38,11 +38,11 @@ resource "boundary_auth_method" "password" {
|
||||
### Optional
|
||||
|
||||
- **description** (String) The auth method description.
|
||||
- **min_login_name_length** (Number) The minimum login name length.
|
||||
- **min_password_length** (Number) The minimum password length.
|
||||
- **min_login_name_length** (Number, Deprecated) The minimum login name length.
|
||||
- **min_password_length** (Number, Deprecated) The minimum password length.
|
||||
- **name** (String) The auth method name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the account.
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "boundary_auth_method_oidc Resource - terraform-provider-boundary"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
The OIDC auth method resource allows you to configure a Boundary authmethodoidc.
|
||||
---
|
||||
|
||||
# boundary_auth_method_oidc (Resource)
|
||||
|
||||
The OIDC auth method resource allows you to configure a Boundary auth_method_oidc.
|
||||
|
||||
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- **scope_id** (String) The scope ID.
|
||||
|
||||
### Optional
|
||||
|
||||
- **allowed_audiences** (List of String) Audiences for which the provider responses will be allowed
|
||||
- **api_url_prefix** (String) The API prefix to use when generating callback URLs for the provider. Should be set to an address at which the provider can reach back to the controller.
|
||||
- **callback_url** (String) The URL that should be provided to the IdP for callbacks.
|
||||
- **client_id** (String) The client ID assigned to this auth method from the provider.
|
||||
- **client_secret** (String) The secret key assigned to this auth method from the provider. Once set, only the hash will be kept and the original value can be removed from configuration.
|
||||
- **client_secret_hmac** (String) The HMAC of the client secret returned by the Boundary controller, which is used for comparison after initial setting of the value.
|
||||
- **description** (String) The auth method description.
|
||||
- **disable_discovered_config_validation** (Boolean) Disables validation logic ensuring that the OIDC provider's information from its discovery endpoint matches the information here. The validation is only performed at create or update time.
|
||||
- **idp_ca_certs** (List of String) A list of CA certificates to trust when validating the IdP's token signatures.
|
||||
- **is_primary_for_scope** (Boolean) When true, makes this auth method the primary auth method for the scope in which it resides. The primary auth method for a scope means the the user will be automatically created when they login using an OIDC account.
|
||||
- **issuer** (String) The issuer corresponding to the provider, which must match the issuer field in generated tokens.
|
||||
- **max_age** (Number) The max age to provide to the provider, indicating how much time is allowed to have passed since the last authentication before the user is challenged again.
|
||||
- **name** (String) The auth method name. Defaults to the resource name.
|
||||
- **signing_algorithms** (List of String) Allowed signing algorithms for the provider's issued tokens.
|
||||
- **state** (String) Can be one of 'inactive', 'active-private', or 'active-public'. Currently automatically set to active-public.
|
||||
- **type** (String) The type of auth method; hardcoded.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the auth method.
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "boundary_auth_method_password Resource - terraform-provider-boundary"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
The auth method resource allows you to configure a Boundary authmethodpassword.
|
||||
---
|
||||
|
||||
# boundary_auth_method_password (Resource)
|
||||
|
||||
The auth method resource allows you to configure a Boundary auth_method_password.
|
||||
|
||||
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- **scope_id** (String) The scope ID.
|
||||
|
||||
### Optional
|
||||
|
||||
- **description** (String) The auth method description.
|
||||
- **min_login_name_length** (Number) The minimum login name length.
|
||||
- **min_password_length** (Number) The minimum password length.
|
||||
- **name** (String) The auth method name. Defaults to the resource name.
|
||||
- **type** (String) The resource type, hardcoded per resource
|
||||
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the account.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ resource "boundary_group" "example" {
|
||||
- **member_ids** (Set of String) Resource IDs for group members, these are most likely boundary users.
|
||||
- **name** (String) The group name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the group.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The host resource allows you to configure a Boundary static host. Hosts are always part of a project, so a project resource should be used inline or you should have the project ID in hand to successfully configure a host.
|
||||
---
|
||||
|
||||
# Resource `boundary_host`
|
||||
# boundary_host (Resource)
|
||||
|
||||
The host resource allows you to configure a Boundary static host. Hosts are always part of a project, so a project resource should be used inline or you should have the project ID in hand to successfully configure a host.
|
||||
|
||||
@@ -50,7 +50,7 @@ resource "boundary_host" "example" {
|
||||
- **description** (String) The host description.
|
||||
- **name** (String) The host name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the host.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The host catalog resource allows you to configure a Boundary host catalog. Host catalogs are always part of a project, so a project resource should be used inline or you should have the project ID in hand to successfully configure a host catalog.
|
||||
---
|
||||
|
||||
# Resource `boundary_host_catalog`
|
||||
# boundary_host_catalog (Resource)
|
||||
|
||||
The host catalog resource allows you to configure a Boundary host catalog. Host catalogs are always part of a project, so a project resource should be used inline or you should have the project ID in hand to successfully configure a host catalog.
|
||||
|
||||
@@ -49,7 +49,7 @@ resource "boundary_host_catalog" "example" {
|
||||
- **description** (String) The host catalog description.
|
||||
- **name** (String) The host catalog name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the host catalog.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The host_set resource allows you to configure a Boundary host set. Host sets are always part of a host catalog, so a host catalog resource should be used inline or you should have the host catalog ID in hand to successfully configure a host set.
|
||||
---
|
||||
|
||||
# Resource `boundary_host_set`
|
||||
# boundary_host_set (Resource)
|
||||
|
||||
The host_set resource allows you to configure a Boundary host set. Host sets are always part of a host catalog, so a host catalog resource should be used inline or you should have the host catalog ID in hand to successfully configure a host set.
|
||||
|
||||
@@ -71,7 +71,7 @@ resource "boundary_host_set" "web" {
|
||||
- **host_ids** (Set of String) The list of host IDs contained in this set.
|
||||
- **name** (String) The hostset name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the hostset.
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ resource "boundary_role" "readonly" {
|
||||
- **name** (String) The role name. Defaults to the resource name.
|
||||
- **principal_ids** (Set of String) A list of principal (user or group) IDs to add as principals on the role.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the role.
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ resource "boundary_role" "org_admin" {
|
||||
- **global_scope** (Boolean) Indicates that the scope containing this value is the global scope, which triggers some specialized behavior to allow it to be imported and managed.
|
||||
- **name** (String) The scope name. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the scope.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The target resource allows you to configure a Boundary target.
|
||||
---
|
||||
|
||||
# Resource `boundary_target`
|
||||
# boundary_target (Resource)
|
||||
|
||||
The target resource allows you to configure a Boundary target.
|
||||
|
||||
@@ -93,7 +93,7 @@ resource "boundary_target" "foo" {
|
||||
- **session_max_seconds** (Number)
|
||||
- **worker_filter** (String) Boolean expression to filter the workers for this target
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the target.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |-
|
||||
The user resource allows you to configure a Boundary user.
|
||||
---
|
||||
|
||||
# Resource `boundary_user`
|
||||
# boundary_user (Resource)
|
||||
|
||||
The user resource allows you to configure a Boundary user.
|
||||
|
||||
@@ -54,7 +54,7 @@ resource "boundary_user" "jeff" {
|
||||
- **description** (String) The user description.
|
||||
- **name** (String) The username. Defaults to the resource name.
|
||||
|
||||
### Read-only
|
||||
### Read-Only
|
||||
|
||||
- **id** (String) The ID of the user.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/hashicorp/terraform-provider-boundary
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.68.0 // indirect
|
||||
@@ -17,15 +17,16 @@ require (
|
||||
github.com/circonus-labs/circonusllhist v0.1.4 // indirect
|
||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
||||
github.com/golang/snappy v0.0.2 // indirect
|
||||
github.com/hashicorp/boundary v0.1.5
|
||||
github.com/hashicorp/boundary/api v0.0.4
|
||||
github.com/hashicorp/boundary/sdk v0.0.2
|
||||
github.com/hashicorp/boundary v0.2.0
|
||||
github.com/hashicorp/boundary/api v0.0.10
|
||||
github.com/hashicorp/boundary/sdk v0.0.4
|
||||
github.com/hashicorp/cap v0.0.0-20210408110729-0dd65efe5473
|
||||
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
||||
github.com/hashicorp/go-kms-wrapping v0.6.0
|
||||
github.com/hashicorp/go-kms-wrapping v0.6.1
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.6.0 // indirect
|
||||
github.com/hashicorp/terraform-plugin-docs v0.3.1
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.5-0.20201016174159-3a1c6c51f716
|
||||
github.com/hashicorp/terraform-plugin-docs v0.4.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1
|
||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
@@ -34,6 +35,7 @@ require (
|
||||
github.com/prometheus/common v0.14.0 // indirect
|
||||
github.com/prometheus/procfs v0.2.0 // indirect
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c // indirect
|
||||
github.com/zclconf/go-cty v1.6.1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
@@ -54,16 +54,20 @@ func New() *schema.Provider {
|
||||
},
|
||||
},
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"boundary_account": resourceAccount(),
|
||||
"boundary_auth_method": resourceAuthMethod(),
|
||||
"boundary_group": resourceGroup(),
|
||||
"boundary_host": resourceHost(),
|
||||
"boundary_host_catalog": resourceHostCatalog(),
|
||||
"boundary_host_set": resourceHostset(),
|
||||
"boundary_role": resourceRole(),
|
||||
"boundary_scope": resourceScope(),
|
||||
"boundary_target": resourceTarget(),
|
||||
"boundary_user": resourceUser(),
|
||||
"boundary_account": resourceAccount(),
|
||||
"boundary_account_password": resourceAccountPassword(),
|
||||
"boundary_account_oidc": resourceAccountOidc(),
|
||||
"boundary_auth_method": resourceAuthMethod(),
|
||||
"boundary_auth_method_password": resourceAuthMethodPassword(),
|
||||
"boundary_auth_method_oidc": resourceAuthMethodOidc(),
|
||||
"boundary_group": resourceGroup(),
|
||||
"boundary_host": resourceHost(),
|
||||
"boundary_host_catalog": resourceHostCatalog(),
|
||||
"boundary_host_set": resourceHostset(),
|
||||
"boundary_role": resourceRole(),
|
||||
"boundary_scope": resourceScope(),
|
||||
"boundary_target": resourceTarget(),
|
||||
"boundary_user": resourceUser(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -133,11 +137,11 @@ func providerAuthenticate(ctx context.Context, d *schema.ResourceData, md *metaD
|
||||
|
||||
am := authmethods.NewClient(md.client)
|
||||
|
||||
at, err := am.Authenticate(ctx, authMethodId.(string), credentials)
|
||||
at, err := am.Authenticate(ctx, authMethodId.(string), "login", credentials)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
md.client.SetToken(at.Item.Token)
|
||||
md.client.SetToken(at.Attributes["token"].(string))
|
||||
|
||||
default:
|
||||
return errors.New("no suitable auth method information found")
|
||||
@@ -154,7 +158,9 @@ func providerConfigure(p *schema.Provider) schema.ConfigureContextFunc {
|
||||
}
|
||||
|
||||
if url, ok := d.GetOk("addr"); ok {
|
||||
client.SetAddr(url.(string))
|
||||
if err := client.SetAddr(url.(string)); err != nil {
|
||||
return nil, diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if client.Addr() == "" {
|
||||
return nil, diag.Errorf(`"no valid address could be determined from "addr" or "BOUNDARY_ADDR" env var`)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
tcLoginName = "user"
|
||||
tcLoginName = "testuser"
|
||||
tcPassword = "passpass"
|
||||
tcPAUM = "ampw_0000000000"
|
||||
tcConfig = []controller.Option{
|
||||
|
||||
@@ -10,12 +10,6 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
accountTypePassword = "password"
|
||||
accountLoginNameKey = "login_name"
|
||||
accountPasswordKey = "password"
|
||||
)
|
||||
|
||||
func resourceAccount() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The account resource allows you to configure a Boundary account.",
|
||||
@@ -60,11 +54,14 @@ func resourceAccount() *schema.Resource {
|
||||
Description: "The login name for this account.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
},
|
||||
accountPasswordKey: {
|
||||
Description: "The account password. Only set on create, changes will not be reflected when updating account.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
if d.Id() == "" {
|
||||
// This is a new resource do not suppress password diff
|
||||
@@ -77,21 +74,33 @@ func resourceAccount() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromAccountResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(AuthMethodIdKey, raw["auth_method_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
func setFromAccountResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(AuthMethodIdKey, raw["auth_method_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(malnick) - remove after deprecation cycle in favor of attributes
|
||||
switch raw["type"].(string) {
|
||||
case accountTypePassword:
|
||||
if attrsVal, ok := raw["attributes"]; ok {
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
d.Set(accountLoginNameKey, attrs["login_name"])
|
||||
if err := d.Set(accountLoginNameKey, attrs["login_name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -104,49 +113,24 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
return diag.Errorf("no auth method ID provided")
|
||||
}
|
||||
|
||||
var loginName *string
|
||||
if keyVal, ok := d.GetOk(accountLoginNameKey); ok {
|
||||
key := keyVal.(string)
|
||||
loginName = &key
|
||||
}
|
||||
|
||||
var password *string
|
||||
if keyVal, ok := d.GetOk(accountPasswordKey); ok {
|
||||
key := keyVal.(string)
|
||||
password = &key
|
||||
}
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
var typeStr string
|
||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||
typeStr = typeVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no type provided")
|
||||
}
|
||||
switch typeStr {
|
||||
case accountTypePassword:
|
||||
if loginName != nil {
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(*loginName))
|
||||
}
|
||||
if password != nil {
|
||||
opts = append(opts, accounts.WithPasswordAccountPassword(*password))
|
||||
d.Set(accountPasswordKey, *password)
|
||||
}
|
||||
default:
|
||||
return diag.Errorf("invalid type provided")
|
||||
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||
opts = append(opts, accounts.WithName(nameVal.(string)))
|
||||
}
|
||||
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
opts = append(opts, accounts.WithName(nameStr))
|
||||
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||
opts = append(opts, accounts.WithDescription(descVal.(string)))
|
||||
}
|
||||
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
opts = append(opts, accounts.WithDescription(descStr))
|
||||
// TODO(malnick) - remove after deprecation cycle
|
||||
if name, ok := d.GetOk(accountLoginNameKey); ok {
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(name.(string)))
|
||||
}
|
||||
|
||||
// TODO(malnick) - remove after deprecation cycle
|
||||
if pass, ok := d.GetOk(accountPasswordKey); ok {
|
||||
opts = append(opts, accounts.WithPasswordAccountPassword(pass.(string)))
|
||||
}
|
||||
|
||||
aClient := accounts.NewClient(md.client)
|
||||
@@ -159,7 +143,9 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
return diag.Errorf("nil account after create")
|
||||
}
|
||||
|
||||
setFromAccountResponseMap(d, acr.GetResponseMap())
|
||||
if err := setFromAccountResponseMap(d, acr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -170,7 +156,7 @@ func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
|
||||
arr, err := aClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -180,7 +166,9 @@ func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
return diag.Errorf("account nil after read")
|
||||
}
|
||||
|
||||
setFromAccountResponseMap(d, arr.GetResponseMap())
|
||||
if err := setFromAccountResponseMap(d, arr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -191,60 +179,38 @@ func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
var name *string
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, accounts.DefaultName())
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
name = &nameStr
|
||||
opts = append(opts, accounts.WithName(nameStr))
|
||||
opts = append(opts, accounts.WithName(nameVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
var desc *string
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, accounts.DefaultDescription())
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
desc = &descStr
|
||||
opts = append(opts, accounts.WithDescription(descStr))
|
||||
opts = append(opts, accounts.WithDescription(descVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
var loginName *string
|
||||
// TODO(malnick) - remove after deprecation cycle
|
||||
if d.HasChange(accountLoginNameKey) {
|
||||
switch d.Get(TypeKey).(string) {
|
||||
case accountTypePassword:
|
||||
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
|
||||
keyVal, ok := d.GetOk(accountLoginNameKey)
|
||||
if ok {
|
||||
keyStr := keyVal.(string)
|
||||
loginName = &keyStr
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(keyStr))
|
||||
}
|
||||
default:
|
||||
return diag.Errorf(`"login_name" cannot be used with this type of account`)
|
||||
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
|
||||
if keyVal, ok := d.GetOk(accountLoginNameKey); ok {
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(keyVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, accounts.WithAutomaticVersioning(true))
|
||||
_, err := aClient.Update(ctx, d.Id(), 0, opts...)
|
||||
aur, err := aClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating account: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
}
|
||||
if d.HasChange(accountLoginNameKey) {
|
||||
d.Set(accountLoginNameKey, loginName)
|
||||
setFromAccountResponseMap(d, aur.GetResponse().Map)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/accounts"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
accountTypeOidc = "password"
|
||||
accountOidcIssuerKey = "issuer"
|
||||
accountOidcSubjectKey = "subject"
|
||||
)
|
||||
|
||||
func resourceAccountOidc() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The account resource allows you to configure a Boundary account.",
|
||||
|
||||
CreateContext: resourceAccountOidcCreate,
|
||||
ReadContext: resourceAccountOidcRead,
|
||||
UpdateContext: resourceAccountOidcUpdate,
|
||||
DeleteContext: resourceAccountOidcDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
StateContext: schema.ImportStatePassthroughContext,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
IDKey: {
|
||||
Description: "The ID of the account.",
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
NameKey: {
|
||||
Description: "The account name. Defaults to the resource name.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
DescriptionKey: {
|
||||
Description: "The account description.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
AuthMethodIdKey: {
|
||||
Description: "The resource ID for the auth method.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
accountOidcIssuerKey: {
|
||||
Description: "The OIDC issuer.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
accountOidcSubjectKey: {
|
||||
Description: "The OIDC subject.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setFromAccountOidcResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(AuthMethodIdKey, raw["auth_method_id"])
|
||||
d.Set(accountOidcIssuerKey, raw["issuer"])
|
||||
d.Set(accountOidcSubjectKey, raw["subject"])
|
||||
d.SetId(raw["id"].(string))
|
||||
}
|
||||
|
||||
func resourceAccountOidcCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
|
||||
var authMethodId string
|
||||
if authMethodIdVal, ok := d.GetOk(AuthMethodIdKey); ok {
|
||||
authMethodId = authMethodIdVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no auth method ID provided")
|
||||
}
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
if i, ok := d.GetOk(accountOidcIssuerKey); ok {
|
||||
opts = append(opts, accounts.WithOidcAccountIssuer(i.(string)))
|
||||
}
|
||||
|
||||
if s, ok := d.GetOk(accountOidcSubjectKey); ok {
|
||||
opts = append(opts, accounts.WithOidcAccountSubject(s.(string)))
|
||||
}
|
||||
|
||||
if n, ok := d.GetOk(NameKey); ok {
|
||||
opts = append(opts, accounts.WithName(n.(string)))
|
||||
}
|
||||
|
||||
if d, ok := d.GetOk(DescriptionKey); ok {
|
||||
opts = append(opts, accounts.WithDescription(d.(string)))
|
||||
}
|
||||
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
acr, err := aClient.Create(ctx, authMethodId, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error creating account: %v", err)
|
||||
}
|
||||
if acr == nil {
|
||||
return diag.Errorf("nil account after create")
|
||||
}
|
||||
|
||||
setFromAccountOidcResponseMap(d, acr.GetResponse().Map)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountOidcRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
arr, err := aClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return diag.Errorf("error reading account: %v", err)
|
||||
}
|
||||
if arr == nil {
|
||||
return diag.Errorf("account nil after read")
|
||||
}
|
||||
|
||||
setFromAccountOidcResponseMap(d, arr.GetResponse().Map)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountOidcUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, accounts.DefaultName())
|
||||
if n, ok := d.GetOk(NameKey); ok {
|
||||
opts = append(opts, accounts.WithName(n.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, accounts.DefaultDescription())
|
||||
if d, ok := d.GetOk(DescriptionKey); ok {
|
||||
opts = append(opts, accounts.WithDescription(d.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(accountOidcIssuerKey) {
|
||||
opts = append(opts, accounts.DefaultOidcAccountIssuer())
|
||||
if i, ok := d.GetOk(accountOidcIssuerKey); ok {
|
||||
opts = append(opts, accounts.WithOidcAccountIssuer(i.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(accountOidcSubjectKey) {
|
||||
opts = append(opts, accounts.DefaultOidcAccountSubject())
|
||||
if i, ok := d.GetOk(accountOidcSubjectKey); ok {
|
||||
opts = append(opts, accounts.WithOidcAccountSubject(i.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, accounts.WithAutomaticVersioning(true))
|
||||
aur, err := aClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating account: %v", err)
|
||||
}
|
||||
|
||||
setFromAccountOidcResponseMap(d, aur.GetResponse().Map)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountOidcDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
_, err := aClient.Delete(ctx, d.Id())
|
||||
if err != nil {
|
||||
return diag.Errorf("error deleting account: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/accounts"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
accountTypePassword = "password"
|
||||
accountLoginNameKey = "login_name"
|
||||
accountPasswordKey = "password"
|
||||
)
|
||||
|
||||
func resourceAccountPassword() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The account resource allows you to configure a Boundary account.",
|
||||
|
||||
CreateContext: resourceAccountPasswordCreate,
|
||||
ReadContext: resourceAccountPasswordRead,
|
||||
UpdateContext: resourceAccountPasswordUpdate,
|
||||
DeleteContext: resourceAccountPasswordDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
StateContext: schema.ImportStatePassthroughContext,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
IDKey: {
|
||||
Description: "The ID of the account.",
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
NameKey: {
|
||||
Description: "The account name. Defaults to the resource name.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
DescriptionKey: {
|
||||
Description: "The account description.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
AuthMethodIdKey: {
|
||||
Description: "The resource ID for the auth method.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
TypeKey: {
|
||||
Description: "The resource type.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
accountLoginNameKey: {
|
||||
Description: "The login name for this account.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
},
|
||||
accountPasswordKey: {
|
||||
Description: "The account password. Only set on create, changes will not be reflected when updating account.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
if d.Id() == "" {
|
||||
// This is a new resource do not suppress password diff
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setFromAccountPasswordResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(AuthMethodIdKey, raw["auth_method_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
|
||||
switch raw["type"].(string) {
|
||||
case accountTypePassword:
|
||||
if attrsVal, ok := raw["attributes"]; ok {
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
d.Set(accountLoginNameKey, attrs["login_name"])
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
}
|
||||
|
||||
func resourceAccountPasswordCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
|
||||
var authMethodId string
|
||||
if authMethodIdVal, ok := d.GetOk(AuthMethodIdKey); ok {
|
||||
authMethodId = authMethodIdVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no auth method ID provided")
|
||||
}
|
||||
|
||||
var loginName *string
|
||||
if keyVal, ok := d.GetOk(accountLoginNameKey); ok {
|
||||
key := keyVal.(string)
|
||||
loginName = &key
|
||||
}
|
||||
|
||||
var password *string
|
||||
if keyVal, ok := d.GetOk(accountPasswordKey); ok {
|
||||
key := keyVal.(string)
|
||||
password = &key
|
||||
}
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
var typeStr string
|
||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||
typeStr = typeVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no type provided")
|
||||
}
|
||||
switch typeStr {
|
||||
case accountTypePassword:
|
||||
if loginName != nil {
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(*loginName))
|
||||
}
|
||||
if password != nil {
|
||||
opts = append(opts, accounts.WithPasswordAccountPassword(*password))
|
||||
d.Set(accountPasswordKey, *password)
|
||||
}
|
||||
default:
|
||||
return diag.Errorf("invalid type provided")
|
||||
}
|
||||
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
opts = append(opts, accounts.WithName(nameStr))
|
||||
}
|
||||
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
opts = append(opts, accounts.WithDescription(descStr))
|
||||
}
|
||||
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
acr, err := aClient.Create(ctx, authMethodId, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error creating account: %v", err)
|
||||
}
|
||||
if acr == nil {
|
||||
return diag.Errorf("nil account after create")
|
||||
}
|
||||
|
||||
setFromAccountPasswordResponseMap(d, acr.GetResponse().Map)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountPasswordRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
arr, err := aClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return diag.Errorf("error reading account: %v", err)
|
||||
}
|
||||
if arr == nil {
|
||||
return diag.Errorf("account nil after read")
|
||||
}
|
||||
|
||||
setFromAccountPasswordResponseMap(d, arr.GetResponse().Map)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountPasswordUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
opts := []accounts.Option{}
|
||||
|
||||
var name *string
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, accounts.DefaultName())
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
name = &nameStr
|
||||
opts = append(opts, accounts.WithName(nameStr))
|
||||
}
|
||||
}
|
||||
|
||||
var desc *string
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, accounts.DefaultDescription())
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
desc = &descStr
|
||||
opts = append(opts, accounts.WithDescription(descStr))
|
||||
}
|
||||
}
|
||||
|
||||
var loginName *string
|
||||
if d.HasChange(accountLoginNameKey) {
|
||||
switch d.Get(TypeKey).(string) {
|
||||
case accountTypePassword:
|
||||
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
|
||||
keyVal, ok := d.GetOk(accountLoginNameKey)
|
||||
if ok {
|
||||
keyStr := keyVal.(string)
|
||||
loginName = &keyStr
|
||||
opts = append(opts, accounts.WithPasswordAccountLoginName(keyStr))
|
||||
}
|
||||
default:
|
||||
return diag.Errorf(`"login_name" cannot be used with this type of account`)
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, accounts.WithAutomaticVersioning(true))
|
||||
_, err := aClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating account: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
}
|
||||
if d.HasChange(accountLoginNameKey) {
|
||||
d.Set(accountLoginNameKey, loginName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAccountPasswordDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
aClient := accounts.NewClient(md.client)
|
||||
|
||||
_, err := aClient.Delete(ctx, d.Id())
|
||||
if err != nil {
|
||||
return diag.Errorf("error deleting account: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/accounts"
|
||||
"github.com/hashicorp/boundary/testing/controller"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
fooAccountPasswordDesc = "test account"
|
||||
fooAccountPasswordDescUpdate = "test account update"
|
||||
)
|
||||
|
||||
var (
|
||||
fooAccountPassword = fmt.Sprintf(`
|
||||
resource "boundary_auth_method" "foo" {
|
||||
name = "test"
|
||||
description = "test account"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}
|
||||
|
||||
resource "boundary_account_password" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
login_name = "foo"
|
||||
password = "foofoofoo"
|
||||
auth_method_id = boundary_auth_method.foo.id
|
||||
}`, fooAccountPasswordDesc)
|
||||
|
||||
fooAccountPasswordUpdate = fmt.Sprintf(`
|
||||
resource "boundary_auth_method" "foo" {
|
||||
name = "test"
|
||||
description = "test account"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}
|
||||
|
||||
resource "boundary_account_password" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
login_name = "foo"
|
||||
password = "foofoofoo"
|
||||
auth_method_id = boundary_auth_method.foo.id
|
||||
}`, fooAccountPasswordDescUpdate)
|
||||
)
|
||||
|
||||
func TestAccAccount(t *testing.T) {
|
||||
tc := controller.NewTestController(t, tcConfig...)
|
||||
defer tc.Shutdown()
|
||||
url := tc.ApiAddrs()[0]
|
||||
|
||||
var provider *schema.Provider
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
ProviderFactories: providerFactories(&provider),
|
||||
CheckDestroy: testAccCheckAccountPasswordResourceDestroy(t, provider),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
// create
|
||||
Config: testConfig(url, fooOrg, fooAccountPassword),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "description", fooAccountPasswordDesc),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "type", "password"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "login_name", "foo"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "password", "foofoofoo"),
|
||||
testAccCheckAccountPasswordResourceExists(provider, "boundary_account_password.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_account_password.foo", "password"),
|
||||
{
|
||||
// update
|
||||
Config: testConfig(url, fooOrg, fooAccountPasswordUpdate),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "description", fooAccountPasswordDescUpdate),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "type", "password"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "login_name", "foo"),
|
||||
resource.TestCheckResourceAttr("boundary_account_password.foo", "password", "foofoofoo"),
|
||||
testAccCheckAccountPasswordResourceExists(provider, "boundary_account_password.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_account_password.foo", "password"),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAccountPasswordResourceExists(testProvider *schema.Provider, name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
id := rs.Primary.ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
amClient := accounts.NewClient(md.client)
|
||||
|
||||
if _, err := amClient.Read(context.Background(), id); err != nil {
|
||||
return fmt.Errorf("Got an error when reading account %q: %v", id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAccountPasswordResourceDestroy(t *testing.T, testProvider *schema.Provider) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if testProvider.Meta() == nil {
|
||||
t.Fatal("got nil provider metadata")
|
||||
}
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
switch rs.Type {
|
||||
case "boundary_account_password":
|
||||
id := rs.Primary.ID
|
||||
|
||||
amClient := accounts.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed account %q: %v", id, err)
|
||||
}
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ resource "boundary_account" "foo" {
|
||||
}`, fooAccountDescUpdate)
|
||||
)
|
||||
|
||||
func TestAccAccount(t *testing.T) {
|
||||
func TestAccAccountBase(t *testing.T) {
|
||||
tc := controller.NewTestController(t, tcConfig...)
|
||||
defer tc.Shutdown()
|
||||
url := tc.ApiAddrs()[0]
|
||||
@@ -69,7 +69,7 @@ func TestAccAccount(t *testing.T) {
|
||||
CheckDestroy: testAccCheckAccountResourceDestroy(t, provider),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
//create
|
||||
// create
|
||||
Config: testConfig(url, fooOrg, fooAccount),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_account.foo", "description", fooAccountDesc),
|
||||
@@ -137,7 +137,7 @@ func testAccCheckAccountResourceDestroy(t *testing.T, testProvider *schema.Provi
|
||||
amClient := accounts.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed account %q: %v", id, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,6 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
authmethodTypePassword = "password"
|
||||
authmethodMinLoginNameLengthKey = "min_login_name_length"
|
||||
authmethodMinPasswordLengthKey = "min_password_length"
|
||||
)
|
||||
|
||||
func resourceAuthMethod() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The auth method resource allows you to configure a Boundary auth_method.",
|
||||
@@ -62,22 +56,32 @@ func resourceAuthMethod() *schema.Resource {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
},
|
||||
authmethodMinPasswordLengthKey: {
|
||||
Description: "The minimum password length.",
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch raw["type"].(string) {
|
||||
case authmethodTypePassword:
|
||||
@@ -86,15 +90,19 @@ func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interfa
|
||||
|
||||
minLoginNameLength := attrs["min_login_name_length"].(json.Number)
|
||||
minLoginNameLengthInt, _ := minLoginNameLength.Int64()
|
||||
d.Set(authmethodMinLoginNameLengthKey, int(minLoginNameLengthInt))
|
||||
if err := d.Set(authmethodMinLoginNameLengthKey, int(minLoginNameLengthInt)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minPasswordLength := attrs["min_password_length"].(json.Number)
|
||||
minPasswordLengthInt, _ := minPasswordLength.Int64()
|
||||
d.Set(authmethodMinPasswordLengthKey, int(minPasswordLengthInt))
|
||||
if err := d.Set(authmethodMinPasswordLengthKey, int(minPasswordLengthInt)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAuthMethodCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -107,48 +115,31 @@ func resourceAuthMethodCreate(ctx context.Context, d *schema.ResourceData, meta
|
||||
return diag.Errorf("no scope ID provided")
|
||||
}
|
||||
|
||||
var minLoginNameLength *int
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey); ok {
|
||||
minLength := minLengthVal.(int)
|
||||
minLoginNameLength = &minLength
|
||||
}
|
||||
|
||||
var minPasswordLength *int
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||
minLength := minLengthVal.(int)
|
||||
minPasswordLength = &minLength
|
||||
}
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
var typeStr string
|
||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||
typeStr = typeVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no type provided")
|
||||
}
|
||||
switch typeStr {
|
||||
case authmethodTypePassword:
|
||||
if minLoginNameLength != nil {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(*minLoginNameLength)))
|
||||
}
|
||||
if minPasswordLength != nil {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(*minPasswordLength)))
|
||||
}
|
||||
default:
|
||||
return diag.Errorf("invalid type provided")
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||
}
|
||||
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
opts = append(opts, authmethods.WithName(nameStr))
|
||||
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||
}
|
||||
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
opts = append(opts, authmethods.WithDescription(descStr))
|
||||
// TODO(malnick) - deprecate
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey); ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
|
||||
// TODO(malnick) - deprecate
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
@@ -161,7 +152,9 @@ func resourceAuthMethodCreate(ctx context.Context, d *schema.ResourceData, meta
|
||||
return diag.Errorf("nil auth method after create")
|
||||
}
|
||||
|
||||
setFromAuthMethodResponseMap(d, amcr.GetResponseMap())
|
||||
if err := setFromAuthMethodResponseMap(d, amcr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -172,7 +165,7 @@ func resourceAuthMethodRead(ctx context.Context, d *schema.ResourceData, meta in
|
||||
|
||||
amrr, err := amClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -182,7 +175,9 @@ func resourceAuthMethodRead(ctx context.Context, d *schema.ResourceData, meta in
|
||||
return diag.Errorf("auth method nil after read")
|
||||
}
|
||||
|
||||
setFromAuthMethodResponseMap(d, amrr.GetResponseMap())
|
||||
if err := setFromAuthMethodResponseMap(d, amrr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -193,81 +188,43 @@ func resourceAuthMethodUpdate(ctx context.Context, d *schema.ResourceData, meta
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
var name *string
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, authmethods.DefaultName())
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
name = &nameStr
|
||||
opts = append(opts, authmethods.WithName(nameStr))
|
||||
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
var desc *string
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, authmethods.DefaultDescription())
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
desc = &descStr
|
||||
opts = append(opts, authmethods.WithDescription(descStr))
|
||||
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
var minLoginNameLength *int
|
||||
if d.HasChange(authmethodMinLoginNameLengthKey) {
|
||||
switch d.Get(TypeKey).(string) {
|
||||
case authmethodTypePassword:
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinLoginNameLength())
|
||||
minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey)
|
||||
if ok {
|
||||
minLengthInt := minLengthVal.(int)
|
||||
minLoginNameLength = &minLengthInt
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(minLengthInt)))
|
||||
}
|
||||
default:
|
||||
return diag.Errorf(`"min_login_name_length" cannot be used with this type of auth method`)
|
||||
}
|
||||
}
|
||||
|
||||
var minPasswordLength *int
|
||||
// TODO(malnick) - deprecate
|
||||
if d.HasChange(authmethodMinPasswordLengthKey) {
|
||||
switch d.Get(TypeKey).(string) {
|
||||
case authmethodTypePassword:
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinPasswordLength())
|
||||
minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey)
|
||||
if ok {
|
||||
minLengthInt := minLengthVal.(int)
|
||||
minPasswordLength = &minLengthInt
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthInt)))
|
||||
}
|
||||
default:
|
||||
return diag.Errorf(`"min_password_length" cannot be used with this type of auth method`)
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinPasswordLength())
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, authmethods.WithAutomaticVersioning(true))
|
||||
_, err := amClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating auth method: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
}
|
||||
// TODO(malnick) - deprecate
|
||||
if d.HasChange(authmethodMinLoginNameLengthKey) {
|
||||
d.Set(authmethodMinLoginNameLengthKey, minLoginNameLength)
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinLoginNameLength())
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey); ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodMinPasswordLengthKey) {
|
||||
d.Set(authmethodMinPasswordLengthKey, minPasswordLength)
|
||||
|
||||
opts = append(opts, authmethods.WithAutomaticVersioning(true))
|
||||
amu, err := amClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating auth method: %v", err)
|
||||
}
|
||||
|
||||
setFromAuthMethodResponseMap(d, amu.GetResponse().Map)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
authmethodTypeOidc = "oidc"
|
||||
authmethodOidcIssuerKey = "issuer"
|
||||
authmethodOidcClientIdKey = "client_id"
|
||||
authmethodOidcClientSecretKey = "client_secret"
|
||||
authmethodOidcMaxAgeKey = "max_age"
|
||||
authmethodOidcApiUrlPrefixKey = "api_url_prefix"
|
||||
authmethodOidcIdpCaCertsKey = "idp_ca_certs"
|
||||
authmethodOidcAllowedAudiencesKey = "allowed_audiences"
|
||||
authmethodOidcDisableDiscoveredConfigValidationKey = "disable_discovered_config_validation"
|
||||
authmethodOidcSigningAlgorithmsKey = "signing_algorithms"
|
||||
authmethodOidcIsPrimaryAuthMethodForScope = "is_primary_for_scope"
|
||||
|
||||
// computed-only parameters
|
||||
authmethodOidcCallbackUrlKey = "callback_url"
|
||||
authmethodOidcClientSecretHmacKey = "client_secret_hmac"
|
||||
authmethodOidcStateKey = "state"
|
||||
)
|
||||
|
||||
func resourceAuthMethodOidc() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The OIDC auth method resource allows you to configure a Boundary auth_method_oidc.",
|
||||
|
||||
CreateContext: resourceAuthMethodOidcCreate,
|
||||
ReadContext: resourceAuthMethodOidcRead,
|
||||
UpdateContext: resourceAuthMethodOidcUpdate,
|
||||
DeleteContext: resourceAuthMethodOidcDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
StateContext: schema.ImportStatePassthroughContext,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
IDKey: {
|
||||
Description: "The ID of the auth method.",
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
NameKey: {
|
||||
Description: "The auth method name. Defaults to the resource name.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
DescriptionKey: {
|
||||
Description: "The auth method description.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
ScopeIdKey: {
|
||||
Description: "The scope ID.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
// OIDC specific configurable parameters
|
||||
authmethodOidcAllowedAudiencesKey: {
|
||||
Description: "Audiences for which the provider responses will be allowed",
|
||||
Type: schema.TypeList,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcApiUrlPrefixKey: {
|
||||
Description: "The API prefix to use when generating callback URLs for the provider. Should be set to an address at which the provider can reach back to the controller.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcIdpCaCertsKey: {
|
||||
Description: "A list of CA certificates to trust when validating the IdP's token signatures.",
|
||||
Type: schema.TypeList,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcClientIdKey: {
|
||||
Description: "The client ID assigned to this auth method from the provider.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcClientSecretKey: {
|
||||
Description: "The secret key assigned to this auth method from the provider. Once set, only the hash will be kept and the original value can be removed from configuration.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcIssuerKey: {
|
||||
Description: "The issuer corresponding to the provider, which must match the issuer field in generated tokens.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcDisableDiscoveredConfigValidationKey: {
|
||||
Description: "Disables validation logic ensuring that the OIDC provider's information from its discovery endpoint matches the information here. The validation is only performed at create or update time.",
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcMaxAgeKey: {
|
||||
Description: "The max age to provide to the provider, indicating how much time is allowed to have passed since the last authentication before the user is challenged again.",
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodOidcSigningAlgorithmsKey: {
|
||||
Description: "Allowed signing algorithms for the provider's issued tokens.",
|
||||
Type: schema.TypeList,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
// OIDC specific immutable and computed parameters
|
||||
authmethodOidcClientSecretHmacKey: {
|
||||
Description: "The HMAC of the client secret returned by the Boundary controller, which is used for comparison after initial setting of the value.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
authmethodOidcStateKey: {
|
||||
Description: "Can be one of 'inactive', 'active-private', or 'active-public'. Currently automatically set to active-public.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
authmethodOidcCallbackUrlKey: {
|
||||
Description: "The URL that should be provided to the IdP for callbacks.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
authmethodOidcIsPrimaryAuthMethodForScope: {
|
||||
Description: "When true, makes this auth method the primary auth method for the scope in which it resides. The primary auth method for a scope means the the user will be automatically created when they login using an OIDC account.",
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
TypeKey: {
|
||||
Description: "The type of auth method; hardcoded.",
|
||||
Type: schema.TypeString,
|
||||
Default: authmethodTypeOidc,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setFromOidcAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) diag.Diagnostics {
|
||||
d.Set(NameKey, raw[NameKey])
|
||||
d.Set(DescriptionKey, raw[DescriptionKey])
|
||||
d.Set(ScopeIdKey, raw[ScopeIdKey])
|
||||
d.Set(TypeKey, raw[TypeKey])
|
||||
|
||||
if attrsVal, ok := raw["attributes"]; ok {
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
|
||||
// these are always set
|
||||
d.Set(authmethodOidcStateKey, attrs[authmethodOidcStateKey].(string))
|
||||
d.Set(authmethodOidcIssuerKey, attrs[authmethodOidcIssuerKey].(string))
|
||||
d.Set(authmethodOidcClientIdKey, attrs[authmethodOidcClientIdKey].(string))
|
||||
d.Set(authmethodOidcClientSecretHmacKey, attrs[authmethodOidcClientSecretHmacKey].(string))
|
||||
|
||||
if certs, ok := attrs[authmethodOidcIdpCaCertsKey]; ok {
|
||||
d.Set(authmethodOidcIdpCaCertsKey, certs.([]interface{}))
|
||||
}
|
||||
|
||||
if aud, ok := attrs[authmethodOidcAllowedAudiencesKey]; ok {
|
||||
d.Set(authmethodOidcAllowedAudiencesKey, aud.([]interface{}))
|
||||
}
|
||||
|
||||
if m, ok := attrs[authmethodOidcMaxAgeKey]; ok {
|
||||
maxAge := m.(json.Number)
|
||||
maxAgeInt, _ := maxAge.Int64()
|
||||
d.Set(authmethodOidcMaxAgeKey, maxAgeInt)
|
||||
}
|
||||
|
||||
if val, ok := attrs[authmethodOidcApiUrlPrefixKey]; ok {
|
||||
d.Set(authmethodOidcApiUrlPrefixKey, val.(string))
|
||||
}
|
||||
|
||||
if val, ok := attrs[authmethodOidcCallbackUrlKey]; ok {
|
||||
d.Set(authmethodOidcCallbackUrlKey, val.(string))
|
||||
}
|
||||
|
||||
if val, ok := attrs[authmethodOidcSigningAlgorithmsKey]; ok {
|
||||
d.Set(authmethodOidcSigningAlgorithmsKey, val.([]interface{}))
|
||||
}
|
||||
|
||||
if p, ok := attrs[authmethodOidcIsPrimaryAuthMethodForScope]; ok {
|
||||
d.Set(authmethodOidcIsPrimaryAuthMethodForScope, p.(bool))
|
||||
}
|
||||
|
||||
if p, ok := attrs[authmethodOidcDisableDiscoveredConfigValidationKey]; ok {
|
||||
d.Set(authmethodOidcDisableDiscoveredConfigValidationKey, p.(bool))
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAuthMethodOidcCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
|
||||
var typeStr string
|
||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||
typeStr = typeVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no type provided")
|
||||
}
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
opts = append(opts, authmethods.WithAutomaticVersioning(true))
|
||||
|
||||
if issuer, ok := d.GetOk(authmethodOidcIssuerKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodIssuer(issuer.(string)))
|
||||
}
|
||||
if clientId, ok := d.GetOk(authmethodOidcClientIdKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodClientId(clientId.(string)))
|
||||
}
|
||||
if clientSecret, ok := d.GetOk(authmethodOidcClientSecretKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodClientSecret(clientSecret.(string)))
|
||||
}
|
||||
if maxAge, ok := d.GetOk(authmethodOidcMaxAgeKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodMaxAge(uint32(maxAge.(int))))
|
||||
}
|
||||
if prefix, ok := d.GetOk(authmethodOidcApiUrlPrefixKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodApiUrlPrefix(prefix.(string)))
|
||||
}
|
||||
if certs, ok := d.GetOk(authmethodOidcIdpCaCertsKey); ok {
|
||||
certList := []string{}
|
||||
for _, c := range certs.([]interface{}) {
|
||||
certList = append(certList, c.(string))
|
||||
}
|
||||
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodIdpCaCerts(certList))
|
||||
}
|
||||
if aud, ok := d.GetOk(authmethodOidcAllowedAudiencesKey); ok {
|
||||
audList := []string{}
|
||||
for _, c := range aud.([]interface{}) {
|
||||
audList = append(audList, c.(string))
|
||||
}
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodAllowedAudiences(audList))
|
||||
}
|
||||
if dis, ok := d.GetOk(authmethodOidcDisableDiscoveredConfigValidationKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodDisableDiscoveredConfigValidation(dis.(bool)))
|
||||
}
|
||||
if algos, ok := d.GetOk(authmethodOidcSigningAlgorithmsKey); ok {
|
||||
algoList := []string{}
|
||||
for _, c := range algos.([]interface{}) {
|
||||
algoList = append(algoList, c.(string))
|
||||
}
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodSigningAlgorithms(algoList))
|
||||
}
|
||||
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
opts = append(opts, authmethods.WithName(nameStr))
|
||||
}
|
||||
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
opts = append(opts, authmethods.WithDescription(descStr))
|
||||
}
|
||||
|
||||
var scopeId string
|
||||
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||
scopeId = scopeIdVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no scope ID provided")
|
||||
}
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amcr, err := amClient.Create(ctx, typeStr, scopeId, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error creating auth method: %v", err)
|
||||
}
|
||||
if amcr == nil {
|
||||
return diag.Errorf("nil auth method after create")
|
||||
}
|
||||
// need to update state is create was successful to avoid loosing state if the change state or update
|
||||
// scope step that follows errors out
|
||||
if err := setFromOidcAuthMethodResponseMap(d, amcr.GetResponse().Map); err != nil {
|
||||
return diag.Errorf("%v", err)
|
||||
}
|
||||
|
||||
amid := amcr.GetResponse().Map["id"].(string)
|
||||
|
||||
// auto set to active-public state
|
||||
_, err = amClient.ChangeState(ctx, amid, 0, "active-public", authmethods.WithAutomaticVersioning(true))
|
||||
if err != nil {
|
||||
return diag.Errorf("%v", err)
|
||||
}
|
||||
|
||||
// update scope when set to primary
|
||||
if p, ok := d.GetOk(authmethodOidcIsPrimaryAuthMethodForScope); ok {
|
||||
if p.(bool) {
|
||||
if err := updateScopeWithPrimaryAuthMethodId(ctx, scopeId, amid, meta); err != nil {
|
||||
return diag.Errorf("%v", err)
|
||||
}
|
||||
|
||||
amcr.GetResponse().Map[authmethodOidcIsPrimaryAuthMethodForScope] = true
|
||||
}
|
||||
}
|
||||
|
||||
return setFromOidcAuthMethodResponseMap(d, amcr.GetResponse().Map)
|
||||
}
|
||||
|
||||
func updateScopeWithPrimaryAuthMethodId(ctx context.Context, scopeId, authmethodId string, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
scp := scopes.NewClient(md.client)
|
||||
|
||||
opts := []scopes.Option{}
|
||||
opts = append(opts, scopes.WithAutomaticVersioning(true))
|
||||
opts = append(opts, scopes.WithPrimaryAuthMethodId(authmethodId))
|
||||
|
||||
_, err := scp.Update(ctx, scopeId, 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating scope: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readScopeIsPrimaryAuthMethodId(ctx context.Context, scopeId, authmethodId string, meta interface{}) (diag.Diagnostics, bool) {
|
||||
md := meta.(*metaData)
|
||||
scp := scopes.NewClient(md.client)
|
||||
|
||||
srr, err := scp.Read(ctx, scopeId)
|
||||
if err != nil {
|
||||
return diag.Errorf("%s", err), false
|
||||
}
|
||||
|
||||
if p, ok := srr.GetResponse().Map["primary_auth_method_id"]; ok {
|
||||
if p == authmethodId {
|
||||
return nil, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func resourceAuthMethodOidcRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amrr, err := amClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return diag.Errorf("error reading auth method: %v", err)
|
||||
}
|
||||
if amrr == nil {
|
||||
return diag.Errorf("auth method nil after read")
|
||||
}
|
||||
|
||||
serr, isPrimary := readScopeIsPrimaryAuthMethodId(ctx, amrr.GetResponse().Map["scope_id"].(string), amrr.GetResponse().Map["id"].(string), meta)
|
||||
if err != nil {
|
||||
return diag.Errorf("%v", serr)
|
||||
}
|
||||
|
||||
if isPrimary {
|
||||
amrr.GetResponse().Map[authmethodOidcIsPrimaryAuthMethodForScope] = true
|
||||
}
|
||||
|
||||
return setFromOidcAuthMethodResponseMap(d, amrr.GetResponse().Map)
|
||||
}
|
||||
|
||||
func resourceAuthMethodOidcUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, authmethods.DefaultName())
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, authmethods.DefaultDescription())
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(authmethodOidcIssuerKey) {
|
||||
if issuer, ok := d.GetOk(authmethodOidcIssuerKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodIssuer(issuer.(string)))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcClientIdKey) {
|
||||
if clientId, ok := d.GetOk(authmethodOidcClientIdKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodClientId(clientId.(string)))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcClientSecretKey) {
|
||||
if clientSecret, ok := d.GetOk(authmethodOidcClientSecretKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodClientSecret(clientSecret.(string)))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcMaxAgeKey) {
|
||||
if maxAge, ok := d.GetOk(authmethodOidcMaxAgeKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodMaxAge(uint32(maxAge.(int))))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcSigningAlgorithmsKey) {
|
||||
if algos, ok := d.GetOk(authmethodOidcSigningAlgorithmsKey); ok {
|
||||
var signingAlgs []string
|
||||
for _, alg := range algos.([]interface{}) {
|
||||
signingAlgs = append(signingAlgs, alg.(string))
|
||||
}
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodSigningAlgorithms(signingAlgs))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcApiUrlPrefixKey) {
|
||||
if prefix, ok := d.GetOk(authmethodOidcApiUrlPrefixKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodApiUrlPrefix(prefix.(string)))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcClientSecretHmacKey) {
|
||||
if sec, ok := d.GetOk(authmethodOidcClientSecretHmacKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodClientSecret(sec.(string)))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcAllowedAudiencesKey) {
|
||||
if val, ok := d.GetOk(authmethodOidcAllowedAudiencesKey); ok {
|
||||
var audiences []string
|
||||
for _, aud := range val.([]interface{}) {
|
||||
audiences = append(audiences, aud.(string))
|
||||
}
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodAllowedAudiences(audiences))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcIdpCaCertsKey) {
|
||||
if val, ok := d.GetOk(authmethodOidcIdpCaCertsKey); ok {
|
||||
certs := []string{}
|
||||
for _, cert := range val.([]interface{}) {
|
||||
certs = append(certs, cert.(string))
|
||||
}
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodIdpCaCerts(certs))
|
||||
}
|
||||
}
|
||||
if d.HasChange(authmethodOidcDisableDiscoveredConfigValidationKey) {
|
||||
if val, ok := d.GetOk(authmethodOidcDisableDiscoveredConfigValidationKey); ok {
|
||||
opts = append(opts, authmethods.WithOidcAuthMethodDisableDiscoveredConfigValidation(val.(bool)))
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, authmethods.WithAutomaticVersioning(true))
|
||||
amur, err := amClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating auth method: %v", err)
|
||||
}
|
||||
|
||||
if d.HasChange(authmethodOidcIsPrimaryAuthMethodForScope) {
|
||||
if p, ok := d.GetOk(authmethodOidcIsPrimaryAuthMethodForScope); ok {
|
||||
if p.(bool) {
|
||||
if err := updateScopeWithPrimaryAuthMethodId(
|
||||
ctx,
|
||||
amur.GetResponse().Map["scope_id"].(string),
|
||||
amur.GetResponse().Map["id"].(string),
|
||||
meta); err != nil {
|
||||
return diag.Errorf("%v", err)
|
||||
}
|
||||
|
||||
amur.GetResponse().Map[authmethodOidcIsPrimaryAuthMethodForScope] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return setFromOidcAuthMethodResponseMap(d, amur.GetResponse().Map)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAuthMethodOidcDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Delete(ctx, d.Id())
|
||||
if err != nil {
|
||||
return diag.Errorf("error deleting auth method: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"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"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
fooAuthMethodOidcDesc = "test auth method oidc"
|
||||
fooAuthMethodOidcDescUpdate = "test auth method oidc update"
|
||||
fooAuthMethodOidcCaCerts = `-----BEGIN CERTIFICATE-----
|
||||
MIIDsjCCApoCCQCslgm7fAu/VzANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC
|
||||
VVMxCzAJBgNVBAgMAldBMRMwEQYDVQQHDApCZWxsaW5naGFtMRIwEAYDVQQKDAlI
|
||||
YXNoaUNvcnAxETAPBgNVBAsMCEJvdW5kYXJ5MRswGQYDVQQDDBJib3VuZGFyeXBy
|
||||
b2plY3QuaW8xJTAjBgkqhkiG9w0BCQEWFmptYWxuaWNrQGhhc2hpY29ycC5jb20w
|
||||
HhcNMjEwNDA2MjMzNTIxWhcNMjYwNDA1MjMzNTIxWjCBmjELMAkGA1UEBhMCVVMx
|
||||
CzAJBgNVBAgMAldBMRMwEQYDVQQHDApCZWxsaW5naGFtMRIwEAYDVQQKDAlIYXNo
|
||||
aUNvcnAxETAPBgNVBAsMCEJvdW5kYXJ5MRswGQYDVQQDDBJib3VuZGFyeXByb2pl
|
||||
Y3QuaW8xJTAjBgkqhkiG9w0BCQEWFmptYWxuaWNrQGhhc2hpY29ycC5jb20wggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUa/ZLwYhTQ2hGzlwy/sB9xY9h
|
||||
dM4qzY8DUF3Sin/+J2j59q3/vXZA7PS+o1GhoG1nW3J51zgyNFOY/EKHdtxVBken
|
||||
YTTG+JswzrcTxsMV7/sYDgCLq6W8dPMV72gPH/3dRi3/0KUHtA6rBOf0Shf0f6Sz
|
||||
7VmgTWcNmLvXpHKOs4YkjOL/tyflTgNm5j1dOa53TtwtMyvCcpGrB7PGL8m5+E2U
|
||||
qxOzQ9kWfA6zr4Gl5rIm+Us8Ez3n1yGwjwFBteexk1Fot8zWKhoy7pZ3ZjWRpjwL
|
||||
hfGs5eJs4kERQVAGONt39ZIR6OzOFxAsvI9WrMvxAsdCK63RtF2k4r0X21yDAgMB
|
||||
AAEwDQYJKoZIhvcNAQELBQADggEBAJZcl7Zxjya23IcOV8jZDdCHtqnbcg9TcQb+
|
||||
kpX1uEKJMFJoNmNK1q//nJxG1YBn3G8t9XtO6Kc6egdGHXWnOsM37N9hbYPJ2kW1
|
||||
WWAwqWkQbV3wb0cc6MuU1S9xivOqwM046ZIcjrWR4T4tEUSUfYc3I+Yd8APdapn8
|
||||
vePgWnmi/aSsx9RxVOUrzmVhzgN7rQJZGwnYYnxl4cwy2jxpysmXzg/grfXCZs/V
|
||||
Kkc7Y5Ph6vRQ+vPCeB7QUxHxjlr8aq+rYDIaSiZ+/4+qyme0ergfvZmMSU8A3NNS
|
||||
tYIMds5s2lIqVwOoyzpBEOjWBhUThH+aZu1A5c7Cb7s1eLSRX70=
|
||||
-----END CERTIFICATE-----`
|
||||
)
|
||||
|
||||
var (
|
||||
fooAuthMethodOidc = `
|
||||
resource "boundary_auth_method_oidc" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
|
||||
issuer = "%s"
|
||||
client_id = "foo_id"
|
||||
client_secret = "foo_secret"
|
||||
max_age = 10
|
||||
api_url_prefix = "http://localhost:9200"
|
||||
idp_ca_certs = [
|
||||
<<EOT
|
||||
%s
|
||||
EOT
|
||||
]
|
||||
allowed_audiences = ["foo_aud"]
|
||||
signing_algorithms = ["ES256"]
|
||||
}`
|
||||
|
||||
fooAuthMethodOidcUpdate = `
|
||||
resource "boundary_auth_method_oidc" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
scope_id = boundary_scope.org1.id
|
||||
is_primary_for_scope = true
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
|
||||
issuer = "https://test-update.com"
|
||||
client_id = "foo_id_update"
|
||||
client_secret = "foo_secret_update"
|
||||
max_age = 1
|
||||
api_url_prefix = "http://localhost:9200"
|
||||
idp_ca_certs = [
|
||||
<<EOT
|
||||
%s
|
||||
EOT
|
||||
]
|
||||
allowed_audiences = ["foo_aud_update"]
|
||||
signing_algorithms = ["RS256"]
|
||||
|
||||
// we need to disable this validatin, since the updated issuer isn't discoverable
|
||||
disable_discovered_config_validation = true
|
||||
}`
|
||||
)
|
||||
|
||||
func TestAccAuthMethodOidc(t *testing.T) {
|
||||
tp := oidc.StartTestProvider(t)
|
||||
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)
|
||||
updateConfig := fmt.Sprintf(fooAuthMethodOidcUpdate, fooAuthMethodOidcDescUpdate, fooAuthMethodOidcCaCerts)
|
||||
|
||||
var provider *schema.Provider
|
||||
resource.Test(t, resource.TestCase{
|
||||
ProviderFactories: providerFactories(&provider),
|
||||
CheckDestroy: testAccCheckAuthMethodOidcResourceDestroy(t, provider),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
// create
|
||||
Config: testConfig(url, fooOrg, createConfig),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", "description", fooAuthMethodOidcDesc),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcIssuerKey, tp.Addr()),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcClientIdKey, "foo_id"),
|
||||
testAccCheckAuthMethodOidcAttrAryValueSet(provider, "boundary_auth_method_oidc.foo", authmethodOidcIdpCaCertsKey, []string{tpCert}),
|
||||
testAccCheckAuthMethodOidcAttrAryValueSet(provider, "boundary_auth_method_oidc.foo", authmethodOidcAllowedAudiencesKey, []string{"foo_aud"}),
|
||||
testAccCheckAuthMethodOidcAttrAryValueSet(provider, "boundary_auth_method_oidc.foo", authmethodOidcSigningAlgorithmsKey, []string{"ES256"}),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcMaxAgeKey, "10"),
|
||||
testAccCheckAuthMethodOidcResourceExists(provider, "boundary_auth_method_oidc.foo"),
|
||||
testAccIsPrimaryForScope(provider, "boundary_auth_method_oidc.foo", false),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method_oidc.foo", "client_secret", "is_primary_for_scope"),
|
||||
{
|
||||
// update
|
||||
Config: testConfig(url, fooOrg, updateConfig),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", "description", fooAuthMethodOidcDescUpdate),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcIssuerKey, "https://test-update.com"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcClientIdKey, "foo_id_update"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_oidc.foo", authmethodOidcMaxAgeKey, "1"),
|
||||
testAccCheckAuthMethodOidcAttrAryValueSet(provider, "boundary_auth_method_oidc.foo", authmethodOidcIdpCaCertsKey, []string{fooAuthMethodOidcCaCerts}),
|
||||
testAccCheckAuthMethodOidcAttrAryValueSet(provider, "boundary_auth_method_oidc.foo", authmethodOidcAllowedAudiencesKey, []string{"foo_aud_update"}),
|
||||
testAccCheckAuthMethodOidcResourceExists(provider, "boundary_auth_method_oidc.foo"),
|
||||
testAccIsPrimaryForScope(provider, "boundary_auth_method_oidc.foo", true),
|
||||
testAccCheckAuthMethodOidcResourceExists(provider, "boundary_auth_method_oidc.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method_oidc.foo", "client_secret", "is_primary_for_scope"),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodOidcResourceExists(testProvider *schema.Provider, name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
id := rs.Primary.ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
if _, err := amClient.Read(context.Background(), id); err != nil {
|
||||
return fmt.Errorf("Got an error when reading auth method %q: %w", id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodOidcResourceDestroy(t *testing.T, testProvider *schema.Provider) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if testProvider.Meta() == nil {
|
||||
t.Fatal("got nil provider metadata")
|
||||
}
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
switch rs.Type {
|
||||
case "boundary_auth_method_oidc":
|
||||
id := rs.Primary.ID
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed auth method %q: %v", id, err)
|
||||
}
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodOidcAttrAryValueSet(testProvider *schema.Provider, name string, key string, strAry []string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("auth method resource not found: %s", name)
|
||||
}
|
||||
|
||||
id := rs.Primary.ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("auth method resource ID is not set")
|
||||
}
|
||||
|
||||
md := testProvider.Meta().(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amr, err := amClient.Read(context.Background(), id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Got an error when reading auth method %q: %v", id, err)
|
||||
}
|
||||
|
||||
for _, got := range amr.Item.Attributes[key].([]interface{}) {
|
||||
ok := false
|
||||
for _, expected := range strAry {
|
||||
if strings.TrimSpace(got.(string)) == strings.TrimSpace(expected) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("value not found in boundary\n %s: %s\n", key, got.(string))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccIsPrimaryForScope(tp *schema.Provider, name string, shouldBePrimary bool) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("auth method resource not found: %s", name)
|
||||
}
|
||||
|
||||
amId := rs.Primary.ID
|
||||
if amId == "" {
|
||||
return fmt.Errorf("auth method resource ID is not set")
|
||||
}
|
||||
|
||||
md := tp.Meta().(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amr, err := amClient.Read(context.Background(), amId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Got an error when reading auth method %q: %v", amId, err)
|
||||
}
|
||||
|
||||
amScopeId, ok := amr.GetResponse().Map["scope_id"]
|
||||
if !ok {
|
||||
return fmt.Errorf("scope_id unset on auth method resource")
|
||||
}
|
||||
|
||||
scp := scopes.NewClient(md.client)
|
||||
|
||||
srr, err := scp.Read(context.Background(), amScopeId.(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
primaryScopeAuthMethodId, ok := srr.GetResponse().Map["primary_auth_method_id"]
|
||||
if !ok && shouldBePrimary {
|
||||
return fmt.Errorf("primary_auth_method_id is not set on scope resource response")
|
||||
}
|
||||
|
||||
if shouldBePrimary {
|
||||
if primaryScopeAuthMethodId != amId {
|
||||
return fmt.Errorf("auth method ('%s') should be primary for scope but scope returned '%s' for primary_auth_method_id", amId, primaryScopeAuthMethodId)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
authmethodTypePassword = "password"
|
||||
authmethodMinLoginNameLengthKey = "min_login_name_length"
|
||||
authmethodMinPasswordLengthKey = "min_password_length"
|
||||
)
|
||||
|
||||
func resourceAuthMethodPassword() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "The auth method resource allows you to configure a Boundary auth_method_password.",
|
||||
|
||||
CreateContext: resourceAuthMethodPasswordCreate,
|
||||
ReadContext: resourceAuthMethodPasswordRead,
|
||||
UpdateContext: resourceAuthMethodPasswordUpdate,
|
||||
DeleteContext: resourceAuthMethodPasswordDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
StateContext: schema.ImportStatePassthroughContext,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
IDKey: {
|
||||
Description: "The ID of the account.",
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
NameKey: {
|
||||
Description: "The auth method name. Defaults to the resource name.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
DescriptionKey: {
|
||||
Description: "The auth method description.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
ScopeIdKey: {
|
||||
Description: "The scope ID.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
TypeKey: {
|
||||
Description: "The resource type, hardcoded per resource",
|
||||
Type: schema.TypeString,
|
||||
Default: authmethodTypePassword,
|
||||
Optional: true,
|
||||
},
|
||||
authmethodMinLoginNameLengthKey: {
|
||||
Description: "The minimum login name length.",
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
authmethodMinPasswordLengthKey: {
|
||||
Description: "The minimum password length.",
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setFromPasswordAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) diag.Diagnostics {
|
||||
d.Set(NameKey, raw[NameKey])
|
||||
d.Set(DescriptionKey, raw[DescriptionKey])
|
||||
d.Set(ScopeIdKey, raw[ScopeIdKey])
|
||||
d.Set(TypeKey, raw[TypeKey])
|
||||
|
||||
if attrsVal, ok := raw["attributes"]; ok {
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
|
||||
minLoginNameLength := attrs[authmethodMinLoginNameLengthKey].(json.Number)
|
||||
minLoginNameLengthInt, _ := minLoginNameLength.Int64()
|
||||
d.Set(authmethodMinLoginNameLengthKey, int(minLoginNameLengthInt))
|
||||
|
||||
minPasswordLength := attrs[authmethodMinPasswordLengthKey].(json.Number)
|
||||
minPasswordLengthInt, _ := minPasswordLength.Int64()
|
||||
d.Set(authmethodMinPasswordLengthKey, int(minPasswordLengthInt))
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAuthMethodPasswordCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
|
||||
var typeStr string
|
||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||
typeStr = typeVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no type provided")
|
||||
}
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
var minLoginNameLength *int
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey); ok {
|
||||
minLength := minLengthVal.(int)
|
||||
minLoginNameLength = &minLength
|
||||
}
|
||||
if minLoginNameLength != nil {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(*minLoginNameLength)))
|
||||
}
|
||||
|
||||
var minPasswordLength *int
|
||||
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||
minLength := minLengthVal.(int)
|
||||
minPasswordLength = &minLength
|
||||
}
|
||||
if minPasswordLength != nil {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(*minPasswordLength)))
|
||||
}
|
||||
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
nameStr := nameVal.(string)
|
||||
opts = append(opts, authmethods.WithName(nameStr))
|
||||
}
|
||||
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
descStr := descVal.(string)
|
||||
opts = append(opts, authmethods.WithDescription(descStr))
|
||||
}
|
||||
|
||||
var scopeId string
|
||||
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||
scopeId = scopeIdVal.(string)
|
||||
} else {
|
||||
return diag.Errorf("no scope ID provided")
|
||||
}
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amcr, err := amClient.Create(ctx, typeStr, scopeId, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error creating auth method: %v", err)
|
||||
}
|
||||
if amcr == nil {
|
||||
return diag.Errorf("nil auth method after create")
|
||||
}
|
||||
|
||||
return setFromPasswordAuthMethodResponseMap(d, amcr.GetResponse().Map)
|
||||
}
|
||||
|
||||
func resourceAuthMethodPasswordRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
amrr, err := amClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return diag.Errorf("error reading auth method: %v", err)
|
||||
}
|
||||
if amrr == nil {
|
||||
return diag.Errorf("auth method nil after read")
|
||||
}
|
||||
|
||||
return setFromPasswordAuthMethodResponseMap(d, amrr.GetResponse().Map)
|
||||
}
|
||||
|
||||
func resourceAuthMethodPasswordUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
opts := []authmethods.Option{}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
opts = append(opts, authmethods.DefaultName())
|
||||
nameVal, ok := d.GetOk(NameKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(DescriptionKey) {
|
||||
opts = append(opts, authmethods.DefaultDescription())
|
||||
descVal, ok := d.GetOk(DescriptionKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(authmethodMinLoginNameLengthKey) {
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinLoginNameLength())
|
||||
minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(authmethodMinPasswordLengthKey) {
|
||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinPasswordLength())
|
||||
minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey)
|
||||
if ok {
|
||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthVal.(int))))
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
opts = append(opts, authmethods.WithAutomaticVersioning(true))
|
||||
amur, err := amClient.Update(ctx, d.Id(), 0, opts...)
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating auth method: %v", err)
|
||||
}
|
||||
|
||||
return setFromPasswordAuthMethodResponseMap(d, amur.GetResponse().Map)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAuthMethodPasswordDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
md := meta.(*metaData)
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Delete(ctx, d.Id())
|
||||
if err != nil {
|
||||
return diag.Errorf("error deleting auth method: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/testing/controller"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
fooAuthMethodDesc = "test auth method"
|
||||
fooAuthMethodDescUpdate = "test auth method update"
|
||||
)
|
||||
|
||||
var (
|
||||
fooAuthMethod = fmt.Sprintf(`
|
||||
resource "boundary_auth_method_password" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}`, fooAuthMethodDesc)
|
||||
|
||||
fooAuthMethodUpdate = fmt.Sprintf(`
|
||||
resource "boundary_auth_method_password" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}`, fooAuthMethodDescUpdate)
|
||||
)
|
||||
|
||||
func TestAccAuthMethodPassword(t *testing.T) {
|
||||
tc := controller.NewTestController(t, tcConfig...)
|
||||
defer tc.Shutdown()
|
||||
url := tc.ApiAddrs()[0]
|
||||
|
||||
var provider *schema.Provider
|
||||
resource.Test(t, resource.TestCase{
|
||||
ProviderFactories: providerFactories(&provider),
|
||||
CheckDestroy: testAccCheckAuthMethodResourceDestroy(t, provider),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
// create
|
||||
Config: testConfig(url, fooOrg, fooAuthMethod),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "description", fooAuthMethodDesc),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "type", "password"),
|
||||
testAccCheckAuthMethodResourceExists(provider, "boundary_auth_method_password.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method_password.foo"),
|
||||
{
|
||||
// update
|
||||
Config: testConfig(url, fooOrg, fooAuthMethodUpdate),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "description", fooAuthMethodDescUpdate),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method_password.foo", "type", "password"),
|
||||
testAccCheckAuthMethodResourceExists(provider, "boundary_auth_method_password.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method_password.foo"),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodResourceExists(testProvider *schema.Provider, name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
id := rs.Primary.ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
if _, err := amClient.Read(context.Background(), id); err != nil {
|
||||
return fmt.Errorf("Got an error when reading auth method %q: %w", id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodResourceDestroy(t *testing.T, testProvider *schema.Provider) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if testProvider.Meta() == nil {
|
||||
t.Fatal("got nil provider metadata")
|
||||
}
|
||||
md := testProvider.Meta().(*metaData)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
switch rs.Type {
|
||||
case "boundary_auth_method_password":
|
||||
id := rs.Primary.ID
|
||||
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed auth method %q: %v", id, err)
|
||||
}
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -15,31 +15,33 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
fooAuthMethodDesc = "test auth method"
|
||||
fooAuthMethodDescUpdate = "test auth method update"
|
||||
fooBaseAuthMethodDesc = "test auth method"
|
||||
fooBaseAuthMethodDescUpdate = "test auth method update"
|
||||
)
|
||||
|
||||
// TODO(malnick) - remove these tests after deprecating use of password params in
|
||||
// favor of attributes map
|
||||
var (
|
||||
fooAuthMethod = fmt.Sprintf(`
|
||||
fooBaseAuthMethod = fmt.Sprintf(`
|
||||
resource "boundary_auth_method" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}`, fooAuthMethodDesc)
|
||||
}`, fooBaseAuthMethodDesc)
|
||||
|
||||
fooAuthMethodUpdate = fmt.Sprintf(`
|
||||
fooBaseAuthMethodUpdate = fmt.Sprintf(`
|
||||
resource "boundary_auth_method" "foo" {
|
||||
name = "test"
|
||||
description = "%s"
|
||||
type = "password"
|
||||
scope_id = boundary_scope.org1.id
|
||||
depends_on = [boundary_role.org1_admin]
|
||||
}`, fooAuthMethodDescUpdate)
|
||||
}`, fooBaseAuthMethodDescUpdate)
|
||||
)
|
||||
|
||||
func TestAccAuthMethod(t *testing.T) {
|
||||
func TestAccBaseAuthMethodPassword(t *testing.T) {
|
||||
tc := controller.NewTestController(t, tcConfig...)
|
||||
defer tc.Shutdown()
|
||||
url := tc.ApiAddrs()[0]
|
||||
@@ -50,24 +52,25 @@ func TestAccAuthMethod(t *testing.T) {
|
||||
CheckDestroy: testAccCheckAuthMethodResourceDestroy(t, provider),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
//create
|
||||
Config: testConfig(url, fooOrg, fooAuthMethod),
|
||||
// create
|
||||
Config: testConfig(url, fooOrg, fooBaseAuthMethod),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "description", fooAuthMethodDesc),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "description", fooBaseAuthMethodDesc),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "type", "password"),
|
||||
testAccCheckAuthMethodResourceExists(provider, "boundary_auth_method.foo"),
|
||||
testAccCheckBaseAuthMethodResourceExists(provider, "boundary_auth_method.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method.foo"),
|
||||
|
||||
{
|
||||
// update
|
||||
Config: testConfig(url, fooOrg, fooAuthMethodUpdate),
|
||||
Config: testConfig(url, fooOrg, fooBaseAuthMethodUpdate),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "description", fooAuthMethodDescUpdate),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "description", fooBaseAuthMethodDescUpdate),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "name", "test"),
|
||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "type", "password"),
|
||||
testAccCheckAuthMethodResourceExists(provider, "boundary_auth_method.foo"),
|
||||
testAccCheckBaseAuthMethodResourceExists(provider, "boundary_auth_method.foo"),
|
||||
),
|
||||
},
|
||||
importStep("boundary_auth_method.foo"),
|
||||
@@ -75,7 +78,7 @@ func TestAccAuthMethod(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodResourceExists(testProvider *schema.Provider, name string) resource.TestCheckFunc {
|
||||
func testAccCheckBaseAuthMethodResourceExists(testProvider *schema.Provider, name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
@@ -99,7 +102,7 @@ func testAccCheckAuthMethodResourceExists(testProvider *schema.Provider, name st
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAuthMethodResourceDestroy(t *testing.T, testProvider *schema.Provider) resource.TestCheckFunc {
|
||||
func testAccCheckBaseAuthMethodResourceDestroy(t *testing.T, testProvider *schema.Provider) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if testProvider.Meta() == nil {
|
||||
t.Fatal("got nil provider metadata")
|
||||
@@ -114,7 +117,7 @@ func testAccCheckAuthMethodResourceDestroy(t *testing.T, testProvider *schema.Pr
|
||||
amClient := authmethods.NewClient(md.client)
|
||||
|
||||
_, err := amClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed auth method %q: %v", id, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,12 +58,21 @@ func resourceGroup() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromGroupResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(groupMemberIdsKey, raw["member_ids"])
|
||||
func setFromGroupResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(groupMemberIdsKey, raw["member_ids"]); err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -99,7 +108,7 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
if gcr == nil {
|
||||
return diag.Errorf("group nil after create")
|
||||
}
|
||||
raw := gcr.GetResponseMap()
|
||||
raw := gcr.GetResponse().Map
|
||||
|
||||
if val, ok := d.GetOk(groupMemberIdsKey); ok {
|
||||
list := val.(*schema.Set).List()
|
||||
@@ -114,10 +123,12 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
if gcsmr == nil {
|
||||
return diag.Errorf("group nil after setting members")
|
||||
}
|
||||
raw = gcsmr.GetResponseMap()
|
||||
raw = gcsmr.GetResponse().Map
|
||||
}
|
||||
|
||||
setFromGroupResponseMap(d, raw)
|
||||
if err := setFromGroupResponseMap(d, raw); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -128,7 +139,7 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
||||
|
||||
g, err := grps.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -138,7 +149,9 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
||||
return diag.Errorf("group nil after read")
|
||||
}
|
||||
|
||||
setFromGroupResponseMap(d, g.GetResponseMap())
|
||||
if err := setFromGroupResponseMap(d, g.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -180,10 +193,16 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The above call may not actually happen, so we use d.Id() and automatic
|
||||
@@ -201,7 +220,10 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating members in group: %v", err)
|
||||
}
|
||||
d.Set(groupMemberIdsKey, memberIds)
|
||||
if err := d.Set(groupMemberIdsKey, memberIds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -365,7 +365,7 @@ func testAccCheckGroupResourceDestroy(t *testing.T, testProvider *schema.Provide
|
||||
id := rs.Primary.ID
|
||||
|
||||
_, err := grps.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed resource %q: %v", id, apiErr)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,21 +63,32 @@ func resourceHost() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromHostResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(HostCatalogIdKey, raw["host_catalog_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
func setFromHostResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(HostCatalogIdKey, raw["host_catalog_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch raw["type"].(string) {
|
||||
case hostTypeStatic:
|
||||
if attrsVal, ok := raw["attributes"]; ok {
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
d.Set(hostAddressKey, attrs["address"])
|
||||
if err := d.Set(hostAddressKey, attrs["address"]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceHostCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -140,7 +151,9 @@ func resourceHostCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
return diag.Errorf("host nil after create")
|
||||
}
|
||||
|
||||
setFromHostResponseMap(d, hcr.GetResponseMap())
|
||||
if err := setFromHostResponseMap(d, hcr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -151,7 +164,7 @@ func resourceHostRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
|
||||
hrr, err := hClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -161,7 +174,9 @@ func resourceHostRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
return diag.Errorf("host nil after read")
|
||||
}
|
||||
|
||||
setFromHostResponseMap(d, hrr.GetResponseMap())
|
||||
if err := setFromHostResponseMap(d, hrr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -219,13 +234,19 @@ func resourceHostUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(hostAddressKey) {
|
||||
d.Set(hostAddressKey, *address)
|
||||
if err := d.Set(hostAddressKey, *address); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -60,12 +60,21 @@ func resourceHostCatalog() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromHostCatalogResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
func setFromHostCatalogResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceHostCatalogCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -114,7 +123,9 @@ func resourceHostCatalogCreate(ctx context.Context, d *schema.ResourceData, meta
|
||||
return diag.Errorf("nil host catalog after create")
|
||||
}
|
||||
|
||||
setFromHostCatalogResponseMap(d, hccr.GetResponseMap())
|
||||
if err := setFromHostCatalogResponseMap(d, hccr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -125,7 +136,7 @@ func resourceHostCatalogRead(ctx context.Context, d *schema.ResourceData, meta i
|
||||
|
||||
hcrr, err := hcClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -135,7 +146,9 @@ func resourceHostCatalogRead(ctx context.Context, d *schema.ResourceData, meta i
|
||||
return diag.Errorf("host catalog nil after read")
|
||||
}
|
||||
|
||||
setFromHostCatalogResponseMap(d, hcrr.GetResponseMap())
|
||||
if err := setFromHostCatalogResponseMap(d, hcrr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -177,10 +190,14 @@ func resourceHostCatalogUpdate(ctx context.Context, d *schema.ResourceData, meta
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -108,7 +108,7 @@ func testAccCheckHostCatalogResourceDestroy(t *testing.T, testProvider *schema.P
|
||||
hcClient := hostcatalogs.NewClient(md.client)
|
||||
|
||||
_, err := hcClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed host catalog %q: %v", id, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,13 +65,24 @@ func resourceHostset() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromHostSetResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(HostCatalogIdKey, raw["host_catalog_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
d.Set(hostsetHostIdsKey, raw["host_ids"])
|
||||
func setFromHostSetResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(HostCatalogIdKey, raw["host_catalog_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(hostsetHostIdsKey, raw["host_ids"]); err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceHostsetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -130,7 +141,7 @@ func resourceHostsetCreate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
if hscr == nil {
|
||||
return diag.Errorf("nil host set after create")
|
||||
}
|
||||
raw := hscr.GetResponseMap()
|
||||
raw := hscr.GetResponse().Map
|
||||
|
||||
if hostIds != nil {
|
||||
hsshr, err := hsClient.SetHosts(ctx, hscr.Item.Id, hscr.Item.Version, hostIds)
|
||||
@@ -140,10 +151,12 @@ func resourceHostsetCreate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
if hsshr == nil {
|
||||
return diag.Errorf("nil host set after setting hosts")
|
||||
}
|
||||
raw = hsshr.GetResponseMap()
|
||||
raw = hsshr.GetResponse().Map
|
||||
}
|
||||
|
||||
setFromHostSetResponseMap(d, raw)
|
||||
if err := setFromHostSetResponseMap(d, raw); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -154,7 +167,7 @@ func resourceHostsetRead(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
|
||||
hsrr, err := hsClient.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -164,7 +177,9 @@ func resourceHostsetRead(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
return diag.Errorf("host set nil after read")
|
||||
}
|
||||
|
||||
setFromHostSetResponseMap(d, hsrr.GetResponseMap())
|
||||
if err := setFromHostSetResponseMap(d, hsrr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -206,10 +221,14 @@ func resourceHostsetUpdate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
// The above call may not actually happen, so we use d.Id() and automatic
|
||||
@@ -226,7 +245,9 @@ func resourceHostsetUpdate(ctx context.Context, d *schema.ResourceData, meta int
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating hosts in host set: %v", err)
|
||||
}
|
||||
d.Set(hostsetHostIdsKey, hostIds)
|
||||
if err := d.Set(hostsetHostIdsKey, hostIds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -201,7 +201,7 @@ func testAccCheckHostsetResourceDestroy(t *testing.T, testProvider *schema.Provi
|
||||
hostsetsClient := hostsets.NewClient(md.client)
|
||||
|
||||
_, err := hostsetsClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed host set %q: %v", id, apiErr)
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ func testAccCheckHostResourceDestroy(t *testing.T, testProvider *schema.Provider
|
||||
hostsClient := hosts.NewClient(md.client)
|
||||
|
||||
_, err := hostsClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed host %q: %v", id, apiErr)
|
||||
}
|
||||
|
||||
|
||||
@@ -77,14 +77,27 @@ func resourceRole() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(rolePrincipalIdsKey, raw["principal_ids"])
|
||||
d.Set(roleGrantStringsKey, raw["grant_strings"])
|
||||
d.Set(roleGrantScopeIdKey, raw["grant_scope_id"])
|
||||
func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(rolePrincipalIdsKey, raw["principal_ids"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(roleGrantStringsKey, raw["grant_strings"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(roleGrantScopeIdKey, raw["grant_scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -149,7 +162,7 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if tcr == nil {
|
||||
return diag.Errorf("nil role after create")
|
||||
}
|
||||
raw := tcr.GetResponseMap()
|
||||
raw := tcr.GetResponse().Map
|
||||
|
||||
if principalIds != nil {
|
||||
tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true))
|
||||
@@ -159,7 +172,7 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if tspr == nil {
|
||||
return diag.Errorf("nil role after setting principal IDs")
|
||||
}
|
||||
raw = tspr.GetResponseMap()
|
||||
raw = tspr.GetResponse().Map
|
||||
}
|
||||
|
||||
if grantStrings != nil {
|
||||
@@ -170,10 +183,12 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if tsgr == nil {
|
||||
return diag.Errorf("nil role after setting grant strings")
|
||||
}
|
||||
raw = tsgr.GetResponseMap()
|
||||
raw = tsgr.GetResponse().Map
|
||||
}
|
||||
|
||||
setFromRoleResponseMap(d, raw)
|
||||
if err := setFromRoleResponseMap(d, raw); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -184,7 +199,7 @@ func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
|
||||
trr, err := rc.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -194,7 +209,9 @@ func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
return diag.Errorf("role nil after read")
|
||||
}
|
||||
|
||||
setFromRoleResponseMap(d, trr.GetResponseMap())
|
||||
if err := setFromRoleResponseMap(d, trr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -247,13 +264,19 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(roleGrantScopeIdKey) {
|
||||
d.Set(roleGrantScopeIdKey, grantScopeId)
|
||||
if err := d.Set(roleGrantScopeIdKey, grantScopeId); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(roleGrantStringsKey) {
|
||||
@@ -268,7 +291,9 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating grant strings on role: %v", err)
|
||||
}
|
||||
d.Set(roleGrantStringsKey, grantStrings)
|
||||
if err := d.Set(roleGrantStringsKey, grantStrings); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(rolePrincipalIdsKey) {
|
||||
@@ -283,7 +308,9 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating grant strings on role: %v", err)
|
||||
}
|
||||
d.Set(rolePrincipalIdsKey, principalIds)
|
||||
if err := d.Set(rolePrincipalIdsKey, principalIds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -345,7 +345,7 @@ func testAccCheckRoleDestroyed(testProvider *schema.Provider, name string) resou
|
||||
rolesClient := roles.NewClient(md.client)
|
||||
|
||||
_, err := rolesClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
errs = append(errs, fmt.Sprintf("Role not destroyed %q: %v", id, apiErr))
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ func testAccCheckRoleResourceDestroy(t *testing.T, testProvider *schema.Provider
|
||||
rolesClient := roles.NewClient(md.client)
|
||||
|
||||
_, err := rolesClient.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed role %q: %v", id, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -69,15 +69,25 @@ func resourceScope() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromScopeResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
if d.Id() == "global" {
|
||||
d.Set(ScopeIdKey, "global")
|
||||
} else {
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
func setFromScopeResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if d.Id() == "global" {
|
||||
if err := d.Set(ScopeIdKey, "global"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceScopeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -136,7 +146,9 @@ func resourceScopeCreate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
return diag.Errorf("scope nil after create")
|
||||
}
|
||||
|
||||
setFromScopeResponseMap(d, scr.GetResponseMap())
|
||||
if err := setFromScopeResponseMap(d, scr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -147,7 +159,7 @@ func resourceScopeRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
||||
|
||||
srr, err := scp.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -157,7 +169,9 @@ func resourceScopeRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
||||
return diag.Errorf("scope nil after read")
|
||||
}
|
||||
|
||||
setFromScopeResponseMap(d, srr.GetResponseMap())
|
||||
if err := setFromScopeResponseMap(d, srr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -199,10 +213,14 @@ func resourceScopeUpdate(ctx context.Context, d *schema.ResourceData, meta inter
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -166,7 +166,7 @@ func testAccCheckScopeResourceDestroy(t *testing.T, testProvider *schema.Provide
|
||||
continue
|
||||
}
|
||||
_, err := scp.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed resource %q: %w", id, err)
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -91,15 +91,31 @@ func resourceTarget() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(TypeKey, raw["type"])
|
||||
d.Set(targetHostSetIdsKey, raw["host_set_ids"])
|
||||
d.Set(targetSessionMaxSecondsKey, raw["session_max_seconds"])
|
||||
d.Set(targetSessionConnectionLimitKey, raw["session_connection_limit"])
|
||||
d.Set(targetWorkerFilterKey, raw["worker_filter"])
|
||||
func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(targetHostSetIdsKey, raw["host_set_ids"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(targetSessionMaxSecondsKey, raw["session_max_seconds"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(targetSessionConnectionLimitKey, raw["session_connection_limit"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(targetWorkerFilterKey, raw["worker_filter"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch raw["type"].(string) {
|
||||
case targetTypeTcp:
|
||||
@@ -107,12 +123,15 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
|
||||
attrs := attrsVal.(map[string]interface{})
|
||||
if defPort, ok := attrs["default_port"].(json.Number); ok {
|
||||
defPortInt, _ := defPort.Int64()
|
||||
d.Set(targetDefaultPortKey, int(defPortInt))
|
||||
if err := d.Set(targetDefaultPortKey, int(defPortInt)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -202,17 +221,19 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
|
||||
if tcr == nil {
|
||||
return diag.Errorf("target nil after create")
|
||||
}
|
||||
raw := tcr.GetResponseMap()
|
||||
raw := tcr.GetResponse().Map
|
||||
|
||||
if hostSetIds != nil {
|
||||
tur, err := tc.SetHostSets(ctx, tcr.Item.Id, tcr.Item.Version, hostSetIds)
|
||||
if err != nil {
|
||||
return diag.Errorf("error setting host sets on target: %v", err)
|
||||
}
|
||||
raw = tur.GetResponseMap()
|
||||
raw = tur.GetResponse().Map
|
||||
}
|
||||
|
||||
setFromTargetResponseMap(d, raw)
|
||||
if err := setFromTargetResponseMap(d, raw); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -223,7 +244,7 @@ func resourceTargetRead(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
|
||||
trr, err := tc.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -233,7 +254,9 @@ func resourceTargetRead(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
return diag.Errorf("target nil after read")
|
||||
}
|
||||
|
||||
setFromTargetResponseMap(d, trr.GetResponseMap())
|
||||
if err := setFromTargetResponseMap(d, trr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -328,22 +351,34 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(targetDefaultPortKey) {
|
||||
d.Set(targetDefaultPortKey, defaultPort)
|
||||
if err := d.Set(targetDefaultPortKey, defaultPort); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(targetSessionMaxSecondsKey) {
|
||||
d.Set(targetSessionMaxSecondsKey, sessionMaxSeconds)
|
||||
if err := d.Set(targetSessionMaxSecondsKey, sessionMaxSeconds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(targetSessionConnectionLimitKey) {
|
||||
d.Set(targetSessionConnectionLimitKey, sessionConnectionLimit)
|
||||
if err := d.Set(targetSessionConnectionLimitKey, sessionConnectionLimit); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(targetWorkerFilterKey) {
|
||||
d.Set(targetWorkerFilterKey, workerFilter)
|
||||
if err := d.Set(targetWorkerFilterKey, workerFilter); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
// The above call may not actually happen, so we use d.Id() and automatic
|
||||
@@ -360,7 +395,9 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating host sets in target: %v", err)
|
||||
}
|
||||
d.Set(targetHostSetIdsKey, hostSetIds)
|
||||
if err := d.Set(targetHostSetIdsKey, hostSetIds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -224,7 +224,7 @@ func testAccCheckTargetResourceDestroy(t *testing.T, testProvider *schema.Provid
|
||||
id := rs.Primary.ID
|
||||
|
||||
_, err := tgts.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed target %q: %v", id, apiErr)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,12 +56,21 @@ func resourceUser() *schema.Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func setFromUserResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
||||
d.Set(NameKey, raw["name"])
|
||||
d.Set(DescriptionKey, raw["description"])
|
||||
d.Set(ScopeIdKey, raw["scope_id"])
|
||||
d.Set(userAccountIDsKey, raw["account_ids"])
|
||||
func setFromUserResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set(userAccountIDsKey, raw["account_ids"]); err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(raw["id"].(string))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
@@ -97,7 +106,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if ucr == nil {
|
||||
return diag.Errorf("user nil after create")
|
||||
}
|
||||
raw := ucr.GetResponseMap()
|
||||
raw := ucr.GetResponse().Map
|
||||
|
||||
if val, ok := d.GetOk(userAccountIDsKey); ok {
|
||||
list := val.(*schema.Set).List()
|
||||
@@ -112,10 +121,12 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if usrac == nil {
|
||||
return diag.Errorf("user nil after setting accounts")
|
||||
}
|
||||
raw = usrac.GetResponseMap()
|
||||
raw = usrac.GetResponse().Map
|
||||
}
|
||||
|
||||
setFromUserResponseMap(d, raw)
|
||||
if err := setFromUserResponseMap(d, raw); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -126,7 +137,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
|
||||
urr, err := usrs.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound{
|
||||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
@@ -136,7 +147,9 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
||||
return diag.Errorf("user nil after read")
|
||||
}
|
||||
|
||||
setFromUserResponseMap(d, urr.GetResponseMap())
|
||||
if err := setFromUserResponseMap(d, urr.GetResponse().Map); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -178,10 +191,14 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
}
|
||||
|
||||
if d.HasChange(NameKey) {
|
||||
d.Set(NameKey, name)
|
||||
if err := d.Set(NameKey, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
if d.HasChange(DescriptionKey) {
|
||||
d.Set(DescriptionKey, desc)
|
||||
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange(userAccountIDsKey) {
|
||||
@@ -197,7 +214,9 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
||||
if err != nil {
|
||||
return diag.Errorf("error updating accounts on user: %v", err)
|
||||
}
|
||||
d.Set(userAccountIDsKey, accountIds)
|
||||
if err := d.Set(userAccountIDsKey, accountIds); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -232,7 +232,7 @@ func testAccCheckUserResourceDestroy(t *testing.T, testProvider *schema.Provider
|
||||
usrs := users.NewClient(md.client)
|
||||
|
||||
_, err := usrs.Read(context.Background(), id)
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.ResponseStatus() != http.StatusNotFound {
|
||||
if apiErr := api.AsServerError(err); apiErr == nil || apiErr.Response().StatusCode() != http.StatusNotFound {
|
||||
return fmt.Errorf("didn't get a 404 when reading destroyed user %q: %v", id, err)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user