Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f1cf40e9 | ||
|
|
4f4318d005 | ||
|
|
5af7f8b662 | ||
|
|
3d42195a26 | ||
|
|
9bc08d4c48 | ||
|
|
4de1075067 | ||
|
|
dc46913c63 | ||
|
|
bb85735e02 | ||
|
|
f49ee1d5bc | ||
|
|
b01f482fb2 | ||
|
|
b69e175687 | ||
|
|
3f0d2b2acd | ||
|
|
a2c645304f | ||
|
|
c0aa9bf5b1 | ||
|
|
7403e3648e |
No files matched your search
@@ -7,8 +7,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- add_ssh_keys:
|
- add_ssh_keys:
|
||||||
fingerprints:
|
fingerprints:
|
||||||
# hashicorp-ci github "machine" user, for private modules
|
# hc-github-team-secure-boundary github user,TF_ACC=1 ~/.go/bin/go test ./... -v $(TESTARGS) -timeout 120m to read private modules
|
||||||
- "c6:96:98:82:dc:04:6c:39:dd:ac:83:05:e3:15:1c:98"
|
- "d4:7f:b2:f7:6f:4d:e7:21:cc:d2:b7:6a:8b:68:e6:d4"
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
name: "Run Acceptance Tests"
|
name: "Run Acceptance Tests"
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.15.2
|
1.16.3
|
||||||
+16
-1
@@ -1,3 +1,18 @@
|
|||||||
|
## 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
|
||||||
|
|
||||||
|
* Adds worker filter to target resource
|
||||||
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/76))
|
||||||
|
|
||||||
## 1.0.0 (January 20, 2021)
|
## 1.0.0 (January 20, 2021)
|
||||||
|
|
||||||
We are bumping the version of the Boundary Terraform provider to v1.0.0 and will release new versions of the provider at its own cadence instead of keeping it in lockstep with Boundary.
|
We are bumping the version of the Boundary Terraform provider to v1.0.0 and will release new versions of the provider at its own cadence instead of keeping it in lockstep with Boundary.
|
||||||
@@ -12,7 +27,7 @@ We are bumping the version of the Boundary Terraform provider to v1.0.0 and will
|
|||||||
|
|
||||||
### New and Improved
|
### New and Improved
|
||||||
|
|
||||||
Update to the Boundary Go SDK v0.0.3
|
Update provider to handle new domain errors ([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/63))
|
||||||
|
|
||||||
## 0.1.0 (October 14, 2020)
|
## 0.1.0 (October 14, 2020)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
WORKDIR /go/src/terraform-provider-boundary
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Requirements
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x
|
- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x
|
||||||
- [Go](https://golang.org/doc/install) >= 1.15
|
- [Go](https://golang.org/doc/install) >= 1.16
|
||||||
|
|
||||||
Building The Provider
|
Building The Provider
|
||||||
---------------------
|
---------------------
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
VERSION="1.15"
|
VERSION="1.16"
|
||||||
|
|
||||||
[ -z "$GOROOT" ] && GOROOT="$HOME/.go"
|
[ -z "$GOROOT" ] && GOROOT="$HOME/.go"
|
||||||
[ -z "$GOPATH" ] && GOPATH="$HOME/go"
|
[ -z "$GOPATH" ] && GOPATH="$HOME/go"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: |-
|
|||||||
The account resource allows you to configure a Boundary account.
|
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.
|
The account resource allows you to configure a Boundary account.
|
||||||
|
|
||||||
@@ -45,11 +45,11 @@ resource "boundary_account" "jeff" {
|
|||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- **description** (String) The account description.
|
- **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.
|
- **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.
|
- **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.
|
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.
|
The auth method resource allows you to configure a Boundary auth_method.
|
||||||
|
|
||||||
@@ -38,11 +38,11 @@ resource "boundary_auth_method" "password" {
|
|||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- **description** (String) The auth method description.
|
- **description** (String) The auth method description.
|
||||||
- **min_login_name_length** (Number) The minimum login name length.
|
- **min_login_name_length** (Number, Deprecated) The minimum login name length.
|
||||||
- **min_password_length** (Number) The minimum password length.
|
- **min_password_length** (Number, Deprecated) The minimum password length.
|
||||||
- **name** (String) The auth method name. Defaults to the resource name.
|
- **name** (String) The auth method name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the account.
|
- **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.
|
- **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.
|
- **name** (String) The group name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the group.
|
- **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.
|
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.
|
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.
|
- **description** (String) The host description.
|
||||||
- **name** (String) The host name. Defaults to the resource name.
|
- **name** (String) The host name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the host.
|
- **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.
|
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.
|
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.
|
- **description** (String) The host catalog description.
|
||||||
- **name** (String) The host catalog name. Defaults to the resource name.
|
- **name** (String) The host catalog name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the host catalog.
|
- **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.
|
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.
|
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.
|
- **host_ids** (Set of String) The list of host IDs contained in this set.
|
||||||
- **name** (String) The hostset name. Defaults to the resource name.
|
- **name** (String) The hostset name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the hostset.
|
- **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.
|
- **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.
|
- **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.
|
- **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.
|
- **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.
|
- **name** (String) The scope name. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the scope.
|
- **id** (String) The ID of the scope.
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: |-
|
|||||||
The target resource allows you to configure a Boundary target.
|
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.
|
The target resource allows you to configure a Boundary target.
|
||||||
|
|
||||||
@@ -91,8 +91,9 @@ resource "boundary_target" "foo" {
|
|||||||
- **name** (String) The target name. Defaults to the resource name.
|
- **name** (String) The target name. Defaults to the resource name.
|
||||||
- **session_connection_limit** (Number)
|
- **session_connection_limit** (Number)
|
||||||
- **session_max_seconds** (Number)
|
- **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.
|
- **id** (String) The ID of the target.
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: |-
|
|||||||
The user resource allows you to configure a Boundary user.
|
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.
|
The user resource allows you to configure a Boundary user.
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ resource "boundary_user" "jeff" {
|
|||||||
- **description** (String) The user description.
|
- **description** (String) The user description.
|
||||||
- **name** (String) The username. Defaults to the resource name.
|
- **name** (String) The username. Defaults to the resource name.
|
||||||
|
|
||||||
### Read-only
|
### Read-Only
|
||||||
|
|
||||||
- **id** (String) The ID of the user.
|
- **id** (String) The ID of the user.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/hashicorp/terraform-provider-boundary
|
module github.com/hashicorp/terraform-provider-boundary
|
||||||
|
|
||||||
go 1.15
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.68.0 // indirect
|
cloud.google.com/go v0.68.0 // indirect
|
||||||
@@ -17,15 +17,16 @@ require (
|
|||||||
github.com/circonus-labs/circonusllhist v0.1.4 // indirect
|
github.com/circonus-labs/circonusllhist v0.1.4 // indirect
|
||||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
||||||
github.com/golang/snappy v0.0.2 // indirect
|
github.com/golang/snappy v0.0.2 // indirect
|
||||||
github.com/hashicorp/boundary v0.1.4
|
github.com/hashicorp/boundary v0.2.0
|
||||||
github.com/hashicorp/boundary/api v0.0.3
|
github.com/hashicorp/boundary/api v0.0.10
|
||||||
github.com/hashicorp/boundary/sdk v0.0.1
|
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-immutable-radix v1.3.0 // indirect
|
||||||
github.com/hashicorp/go-kms-wrapping v0.5.16
|
github.com/hashicorp/go-kms-wrapping v0.6.1
|
||||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/hashicorp/hcl/v2 v2.6.0 // indirect
|
github.com/hashicorp/hcl/v2 v2.6.0 // indirect
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.3.1
|
github.com/hashicorp/terraform-plugin-docs v0.4.0
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.5-0.20201016174159-3a1c6c51f716
|
github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1
|
||||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
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/common v0.14.0 // indirect
|
||||||
github.com/prometheus/procfs v0.2.0 // indirect
|
github.com/prometheus/procfs v0.2.0 // indirect
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c // 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/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{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"boundary_account": resourceAccount(),
|
"boundary_account": resourceAccount(),
|
||||||
"boundary_auth_method": resourceAuthMethod(),
|
"boundary_account_password": resourceAccountPassword(),
|
||||||
"boundary_group": resourceGroup(),
|
"boundary_account_oidc": resourceAccountOidc(),
|
||||||
"boundary_host": resourceHost(),
|
"boundary_auth_method": resourceAuthMethod(),
|
||||||
"boundary_host_catalog": resourceHostCatalog(),
|
"boundary_auth_method_password": resourceAuthMethodPassword(),
|
||||||
"boundary_host_set": resourceHostset(),
|
"boundary_auth_method_oidc": resourceAuthMethodOidc(),
|
||||||
"boundary_role": resourceRole(),
|
"boundary_group": resourceGroup(),
|
||||||
"boundary_scope": resourceScope(),
|
"boundary_host": resourceHost(),
|
||||||
"boundary_target": resourceTarget(),
|
"boundary_host_catalog": resourceHostCatalog(),
|
||||||
"boundary_user": resourceUser(),
|
"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)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
md.client.SetToken(at.Item.Token)
|
md.client.SetToken(at.Attributes["token"].(string))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return errors.New("no suitable auth method information found")
|
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 {
|
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() == "" {
|
if client.Addr() == "" {
|
||||||
return nil, diag.Errorf(`"no valid address could be determined from "addr" or "BOUNDARY_ADDR" env var`)
|
return nil, diag.Errorf(`"no valid address could be determined from "addr" or "BOUNDARY_ADDR" env var`)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tcLoginName = "user"
|
tcLoginName = "testuser"
|
||||||
tcPassword = "passpass"
|
tcPassword = "passpass"
|
||||||
tcPAUM = "ampw_0000000000"
|
tcPAUM = "ampw_0000000000"
|
||||||
tcConfig = []controller.Option{
|
tcConfig = []controller.Option{
|
||||||
|
|||||||
@@ -10,12 +10,6 @@ import (
|
|||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
accountTypePassword = "password"
|
|
||||||
accountLoginNameKey = "login_name"
|
|
||||||
accountPasswordKey = "password"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceAccount() *schema.Resource {
|
func resourceAccount() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Description: "The account resource allows you to configure a Boundary account.",
|
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.",
|
Description: "The login name for this account.",
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||||
},
|
},
|
||||||
accountPasswordKey: {
|
accountPasswordKey: {
|
||||||
Description: "The account password. Only set on create, changes will not be reflected when updating account.",
|
Description: "The account password. Only set on create, changes will not be reflected when updating account.",
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||||
|
|
||||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||||
if d.Id() == "" {
|
if d.Id() == "" {
|
||||||
// This is a new resource do not suppress password diff
|
// 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{}) {
|
func setFromAccountResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(AuthMethodIdKey, raw["auth_method_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
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) {
|
switch raw["type"].(string) {
|
||||||
case accountTypePassword:
|
case accountTypePassword:
|
||||||
if attrsVal, ok := raw["attributes"]; ok {
|
if attrsVal, ok := raw["attributes"]; ok {
|
||||||
attrs := attrsVal.(map[string]interface{})
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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")
|
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{}
|
opts := []accounts.Option{}
|
||||||
|
|
||||||
var typeStr string
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
opts = append(opts, accounts.WithName(nameVal.(string)))
|
||||||
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 descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
if ok {
|
opts = append(opts, accounts.WithDescription(descVal.(string)))
|
||||||
nameStr := nameVal.(string)
|
|
||||||
opts = append(opts, accounts.WithName(nameStr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
descVal, ok := d.GetOk(DescriptionKey)
|
// TODO(malnick) - remove after deprecation cycle
|
||||||
if ok {
|
if name, ok := d.GetOk(accountLoginNameKey); ok {
|
||||||
descStr := descVal.(string)
|
opts = append(opts, accounts.WithPasswordAccountLoginName(name.(string)))
|
||||||
opts = append(opts, accounts.WithDescription(descStr))
|
}
|
||||||
|
|
||||||
|
// 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)
|
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")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -170,7 +156,7 @@ func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
|
|
||||||
arr, err := aClient.Read(ctx, d.Id())
|
arr, err := aClient.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -180,7 +166,9 @@ func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
return diag.Errorf("account nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -191,60 +179,38 @@ func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta int
|
|||||||
|
|
||||||
opts := []accounts.Option{}
|
opts := []accounts.Option{}
|
||||||
|
|
||||||
var name *string
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
opts = append(opts, accounts.DefaultName())
|
opts = append(opts, accounts.DefaultName())
|
||||||
nameVal, ok := d.GetOk(NameKey)
|
nameVal, ok := d.GetOk(NameKey)
|
||||||
if ok {
|
if ok {
|
||||||
nameStr := nameVal.(string)
|
opts = append(opts, accounts.WithName(nameVal.(string)))
|
||||||
name = &nameStr
|
|
||||||
opts = append(opts, accounts.WithName(nameStr))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc *string
|
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
opts = append(opts, accounts.DefaultDescription())
|
opts = append(opts, accounts.DefaultDescription())
|
||||||
descVal, ok := d.GetOk(DescriptionKey)
|
descVal, ok := d.GetOk(DescriptionKey)
|
||||||
if ok {
|
if ok {
|
||||||
descStr := descVal.(string)
|
opts = append(opts, accounts.WithDescription(descVal.(string)))
|
||||||
desc = &descStr
|
|
||||||
opts = append(opts, accounts.WithDescription(descStr))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var loginName *string
|
// TODO(malnick) - remove after deprecation cycle
|
||||||
if d.HasChange(accountLoginNameKey) {
|
if d.HasChange(accountLoginNameKey) {
|
||||||
switch d.Get(TypeKey).(string) {
|
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
|
||||||
case accountTypePassword:
|
if keyVal, ok := d.GetOk(accountLoginNameKey); ok {
|
||||||
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
|
opts = append(opts, accounts.WithPasswordAccountLoginName(keyVal.(string)))
|
||||||
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 {
|
if len(opts) > 0 {
|
||||||
opts = append(opts, accounts.WithAutomaticVersioning(true))
|
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 {
|
if err != nil {
|
||||||
return diag.Errorf("error updating account: %v", err)
|
return diag.Errorf("error updating account: %v", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
setFromAccountResponseMap(d, aur.GetResponse().Map)
|
||||||
d.Set(NameKey, name)
|
|
||||||
}
|
|
||||||
if d.HasChange(DescriptionKey) {
|
|
||||||
d.Set(DescriptionKey, desc)
|
|
||||||
}
|
|
||||||
if d.HasChange(accountLoginNameKey) {
|
|
||||||
d.Set(accountLoginNameKey, loginName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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)
|
}`, fooAccountDescUpdate)
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccAccount(t *testing.T) {
|
func TestAccAccountBase(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
defer tc.Shutdown()
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
@@ -69,7 +69,7 @@ func TestAccAccount(t *testing.T) {
|
|||||||
CheckDestroy: testAccCheckAccountResourceDestroy(t, provider),
|
CheckDestroy: testAccCheckAccountResourceDestroy(t, provider),
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
{
|
{
|
||||||
//create
|
// create
|
||||||
Config: testConfig(url, fooOrg, fooAccount),
|
Config: testConfig(url, fooOrg, fooAccount),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("boundary_account.foo", "description", fooAccountDesc),
|
resource.TestCheckResourceAttr("boundary_account.foo", "description", fooAccountDesc),
|
||||||
@@ -137,7 +137,7 @@ func testAccCheckAccountResourceDestroy(t *testing.T, testProvider *schema.Provi
|
|||||||
amClient := accounts.NewClient(md.client)
|
amClient := accounts.NewClient(md.client)
|
||||||
|
|
||||||
_, err := amClient.Read(context.Background(), id)
|
_, 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)
|
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"
|
"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 {
|
func resourceAuthMethod() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Description: "The auth method resource allows you to configure a Boundary auth_method.",
|
Description: "The auth method resource allows you to configure a Boundary auth_method.",
|
||||||
@@ -62,22 +56,32 @@ func resourceAuthMethod() *schema.Resource {
|
|||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||||
},
|
},
|
||||||
authmethodMinPasswordLengthKey: {
|
authmethodMinPasswordLengthKey: {
|
||||||
Description: "The minimum password length.",
|
Description: "The minimum password length.",
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
Deprecated: "Will be removed in favor of using attributes parameter",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
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) {
|
switch raw["type"].(string) {
|
||||||
case authmethodTypePassword:
|
case authmethodTypePassword:
|
||||||
@@ -86,15 +90,19 @@ func setFromAuthMethodResponseMap(d *schema.ResourceData, raw map[string]interfa
|
|||||||
|
|
||||||
minLoginNameLength := attrs["min_login_name_length"].(json.Number)
|
minLoginNameLength := attrs["min_login_name_length"].(json.Number)
|
||||||
minLoginNameLengthInt, _ := minLoginNameLength.Int64()
|
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)
|
minPasswordLength := attrs["min_password_length"].(json.Number)
|
||||||
minPasswordLengthInt, _ := minPasswordLength.Int64()
|
minPasswordLengthInt, _ := minPasswordLength.Int64()
|
||||||
d.Set(authmethodMinPasswordLengthKey, int(minPasswordLengthInt))
|
if err := d.Set(authmethodMinPasswordLengthKey, int(minPasswordLengthInt)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.SetId(raw["id"].(string))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceAuthMethodCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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")
|
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
|
var typeStr string
|
||||||
if typeVal, ok := d.GetOk(TypeKey); ok {
|
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||||
typeStr = typeVal.(string)
|
typeStr = typeVal.(string)
|
||||||
} else {
|
} else {
|
||||||
return diag.Errorf("no type provided")
|
return diag.Errorf("no type provided")
|
||||||
}
|
}
|
||||||
switch typeStr {
|
|
||||||
case authmethodTypePassword:
|
opts := []authmethods.Option{}
|
||||||
if minLoginNameLength != nil {
|
|
||||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(*minLoginNameLength)))
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
}
|
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||||
if minPasswordLength != nil {
|
|
||||||
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(*minPasswordLength)))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return diag.Errorf("invalid type provided")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nameVal, ok := d.GetOk(NameKey)
|
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
if ok {
|
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||||
nameStr := nameVal.(string)
|
|
||||||
opts = append(opts, authmethods.WithName(nameStr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
descVal, ok := d.GetOk(DescriptionKey)
|
// TODO(malnick) - deprecate
|
||||||
if ok {
|
if minLengthVal, ok := d.GetOk(authmethodMinLoginNameLengthKey); ok {
|
||||||
descStr := descVal.(string)
|
opts = append(opts, authmethods.WithPasswordAuthMethodMinLoginNameLength(uint32(minLengthVal.(int))))
|
||||||
opts = append(opts, authmethods.WithDescription(descStr))
|
}
|
||||||
|
|
||||||
|
// TODO(malnick) - deprecate
|
||||||
|
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||||
|
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthVal.(int))))
|
||||||
}
|
}
|
||||||
|
|
||||||
amClient := authmethods.NewClient(md.client)
|
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")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -172,7 +165,7 @@ func resourceAuthMethodRead(ctx context.Context, d *schema.ResourceData, meta in
|
|||||||
|
|
||||||
amrr, err := amClient.Read(ctx, d.Id())
|
amrr, err := amClient.Read(ctx, d.Id())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apiErr := api.AsServerError(err); apiErr.ResponseStatus() == http.StatusNotFound {
|
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -182,7 +175,9 @@ func resourceAuthMethodRead(ctx context.Context, d *schema.ResourceData, meta in
|
|||||||
return diag.Errorf("auth method nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -193,81 +188,43 @@ func resourceAuthMethodUpdate(ctx context.Context, d *schema.ResourceData, meta
|
|||||||
|
|
||||||
opts := []authmethods.Option{}
|
opts := []authmethods.Option{}
|
||||||
|
|
||||||
var name *string
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
opts = append(opts, authmethods.DefaultName())
|
opts = append(opts, authmethods.DefaultName())
|
||||||
nameVal, ok := d.GetOk(NameKey)
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
if ok {
|
opts = append(opts, authmethods.WithName(nameVal.(string)))
|
||||||
nameStr := nameVal.(string)
|
|
||||||
name = &nameStr
|
|
||||||
opts = append(opts, authmethods.WithName(nameStr))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc *string
|
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
opts = append(opts, authmethods.DefaultDescription())
|
opts = append(opts, authmethods.DefaultDescription())
|
||||||
descVal, ok := d.GetOk(DescriptionKey)
|
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
if ok {
|
opts = append(opts, authmethods.WithDescription(descVal.(string)))
|
||||||
descStr := descVal.(string)
|
|
||||||
desc = &descStr
|
|
||||||
opts = append(opts, authmethods.WithDescription(descStr))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var minLoginNameLength *int
|
// TODO(malnick) - deprecate
|
||||||
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
|
|
||||||
if d.HasChange(authmethodMinPasswordLengthKey) {
|
if d.HasChange(authmethodMinPasswordLengthKey) {
|
||||||
switch d.Get(TypeKey).(string) {
|
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinPasswordLength())
|
||||||
case authmethodTypePassword:
|
if minLengthVal, ok := d.GetOk(authmethodMinPasswordLengthKey); ok {
|
||||||
opts = append(opts, authmethods.DefaultPasswordAuthMethodMinPasswordLength())
|
opts = append(opts, authmethods.WithPasswordAuthMethodMinPasswordLength(uint32(minLengthVal.(int))))
|
||||||
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`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO(malnick) - deprecate
|
||||||
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)
|
|
||||||
}
|
|
||||||
if d.HasChange(authmethodMinLoginNameLengthKey) {
|
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
|
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 (
|
const (
|
||||||
fooAuthMethodDesc = "test auth method"
|
fooBaseAuthMethodDesc = "test auth method"
|
||||||
fooAuthMethodDescUpdate = "test auth method update"
|
fooBaseAuthMethodDescUpdate = "test auth method update"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(malnick) - remove these tests after deprecating use of password params in
|
||||||
|
// favor of attributes map
|
||||||
var (
|
var (
|
||||||
fooAuthMethod = fmt.Sprintf(`
|
fooBaseAuthMethod = fmt.Sprintf(`
|
||||||
resource "boundary_auth_method" "foo" {
|
resource "boundary_auth_method" "foo" {
|
||||||
name = "test"
|
name = "test"
|
||||||
description = "%s"
|
description = "%s"
|
||||||
type = "password"
|
type = "password"
|
||||||
scope_id = boundary_scope.org1.id
|
scope_id = boundary_scope.org1.id
|
||||||
depends_on = [boundary_role.org1_admin]
|
depends_on = [boundary_role.org1_admin]
|
||||||
}`, fooAuthMethodDesc)
|
}`, fooBaseAuthMethodDesc)
|
||||||
|
|
||||||
fooAuthMethodUpdate = fmt.Sprintf(`
|
fooBaseAuthMethodUpdate = fmt.Sprintf(`
|
||||||
resource "boundary_auth_method" "foo" {
|
resource "boundary_auth_method" "foo" {
|
||||||
name = "test"
|
name = "test"
|
||||||
description = "%s"
|
description = "%s"
|
||||||
type = "password"
|
type = "password"
|
||||||
scope_id = boundary_scope.org1.id
|
scope_id = boundary_scope.org1.id
|
||||||
depends_on = [boundary_role.org1_admin]
|
depends_on = [boundary_role.org1_admin]
|
||||||
}`, fooAuthMethodDescUpdate)
|
}`, fooBaseAuthMethodDescUpdate)
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccAuthMethod(t *testing.T) {
|
func TestAccBaseAuthMethodPassword(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
defer tc.Shutdown()
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
@@ -50,24 +52,25 @@ func TestAccAuthMethod(t *testing.T) {
|
|||||||
CheckDestroy: testAccCheckAuthMethodResourceDestroy(t, provider),
|
CheckDestroy: testAccCheckAuthMethodResourceDestroy(t, provider),
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
{
|
{
|
||||||
//create
|
// create
|
||||||
Config: testConfig(url, fooOrg, fooAuthMethod),
|
Config: testConfig(url, fooOrg, fooBaseAuthMethod),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
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", "name", "test"),
|
||||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "type", "password"),
|
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"),
|
importStep("boundary_auth_method.foo"),
|
||||||
|
|
||||||
{
|
{
|
||||||
// update
|
// update
|
||||||
Config: testConfig(url, fooOrg, fooAuthMethodUpdate),
|
Config: testConfig(url, fooOrg, fooBaseAuthMethodUpdate),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
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", "name", "test"),
|
||||||
resource.TestCheckResourceAttr("boundary_auth_method.foo", "type", "password"),
|
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"),
|
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 {
|
return func(s *terraform.State) error {
|
||||||
rs, ok := s.RootModule().Resources[name]
|
rs, ok := s.RootModule().Resources[name]
|
||||||
if !ok {
|
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 {
|
return func(s *terraform.State) error {
|
||||||
if testProvider.Meta() == nil {
|
if testProvider.Meta() == nil {
|
||||||
t.Fatal("got nil provider metadata")
|
t.Fatal("got nil provider metadata")
|
||||||
@@ -114,7 +117,7 @@ func testAccCheckAuthMethodResourceDestroy(t *testing.T, testProvider *schema.Pr
|
|||||||
amClient := authmethods.NewClient(md.client)
|
amClient := authmethods.NewClient(md.client)
|
||||||
|
|
||||||
_, err := amClient.Read(context.Background(), id)
|
_, 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)
|
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{}) {
|
func setFromGroupResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(groupMemberIdsKey, raw["member_ids"])
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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 {
|
if gcr == nil {
|
||||||
return diag.Errorf("group nil after create")
|
return diag.Errorf("group nil after create")
|
||||||
}
|
}
|
||||||
raw := gcr.GetResponseMap()
|
raw := gcr.GetResponse().Map
|
||||||
|
|
||||||
if val, ok := d.GetOk(groupMemberIdsKey); ok {
|
if val, ok := d.GetOk(groupMemberIdsKey); ok {
|
||||||
list := val.(*schema.Set).List()
|
list := val.(*schema.Set).List()
|
||||||
@@ -114,10 +123,12 @@ func resourceGroupCreate(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
if gcsmr == nil {
|
if gcsmr == nil {
|
||||||
return diag.Errorf("group nil after setting members")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -128,7 +139,7 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
|||||||
|
|
||||||
g, err := grps.Read(ctx, d.Id())
|
g, err := grps.Read(ctx, d.Id())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apiErr := api.AsServerError(err); apiErr.ResponseStatus() == http.StatusNotFound {
|
if apiErr := api.AsServerError(err); apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -138,7 +149,9 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
|||||||
return diag.Errorf("group nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -180,10 +193,16 @@ func resourceGroupUpdate(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
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
|
// 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 {
|
if err != nil {
|
||||||
return diag.Errorf("error updating members in group: %v", err)
|
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
|
return nil
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ func testAccCheckGroupResourceDestroy(t *testing.T, testProvider *schema.Provide
|
|||||||
id := rs.Primary.ID
|
id := rs.Primary.ID
|
||||||
|
|
||||||
_, err := grps.Read(context.Background(), 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)
|
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{}) {
|
func setFromHostResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(HostCatalogIdKey, raw["host_catalog_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
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) {
|
switch raw["type"].(string) {
|
||||||
case hostTypeStatic:
|
case hostTypeStatic:
|
||||||
if attrsVal, ok := raw["attributes"]; ok {
|
if attrsVal, ok := raw["attributes"]; ok {
|
||||||
attrs := attrsVal.(map[string]interface{})
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceHostCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -151,7 +164,7 @@ func resourceHostRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
|
|
||||||
hrr, err := hClient.Read(ctx, d.Id())
|
hrr, err := hClient.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -161,7 +174,9 @@ func resourceHostRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
return diag.Errorf("host nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -219,13 +234,19 @@ func resourceHostUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(hostAddressKey) {
|
if d.HasChange(hostAddressKey) {
|
||||||
d.Set(hostAddressKey, *address)
|
if err := d.Set(hostAddressKey, *address); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -60,12 +60,21 @@ func resourceHostCatalog() *schema.Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFromHostCatalogResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
func setFromHostCatalogResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceHostCatalogCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -125,7 +136,7 @@ func resourceHostCatalogRead(ctx context.Context, d *schema.ResourceData, meta i
|
|||||||
|
|
||||||
hcrr, err := hcClient.Read(ctx, d.Id())
|
hcrr, err := hcClient.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -135,7 +146,9 @@ func resourceHostCatalogRead(ctx context.Context, d *schema.ResourceData, meta i
|
|||||||
return diag.Errorf("host catalog nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -177,10 +190,14 @@ func resourceHostCatalogUpdate(ctx context.Context, d *schema.ResourceData, meta
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func testAccCheckHostCatalogResourceDestroy(t *testing.T, testProvider *schema.P
|
|||||||
hcClient := hostcatalogs.NewClient(md.client)
|
hcClient := hostcatalogs.NewClient(md.client)
|
||||||
|
|
||||||
_, err := hcClient.Read(context.Background(), id)
|
_, 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)
|
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{}) {
|
func setFromHostSetResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(HostCatalogIdKey, raw["host_catalog_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||||
d.Set(hostsetHostIdsKey, raw["host_ids"])
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceHostsetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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 {
|
if hscr == nil {
|
||||||
return diag.Errorf("nil host set after create")
|
return diag.Errorf("nil host set after create")
|
||||||
}
|
}
|
||||||
raw := hscr.GetResponseMap()
|
raw := hscr.GetResponse().Map
|
||||||
|
|
||||||
if hostIds != nil {
|
if hostIds != nil {
|
||||||
hsshr, err := hsClient.SetHosts(ctx, hscr.Item.Id, hscr.Item.Version, hostIds)
|
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 {
|
if hsshr == nil {
|
||||||
return diag.Errorf("nil host set after setting hosts")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -154,7 +167,7 @@ func resourceHostsetRead(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
|
|
||||||
hsrr, err := hsClient.Read(ctx, d.Id())
|
hsrr, err := hsClient.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -164,7 +177,9 @@ func resourceHostsetRead(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
return diag.Errorf("host set nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -206,10 +221,14 @@ func resourceHostsetUpdate(ctx context.Context, d *schema.ResourceData, meta int
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
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
|
// 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 {
|
if err != nil {
|
||||||
return diag.Errorf("error updating hosts in host set: %v", err)
|
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
|
return nil
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ func testAccCheckHostsetResourceDestroy(t *testing.T, testProvider *schema.Provi
|
|||||||
hostsetsClient := hostsets.NewClient(md.client)
|
hostsetsClient := hostsets.NewClient(md.client)
|
||||||
|
|
||||||
_, err := hostsetsClient.Read(context.Background(), id)
|
_, 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)
|
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)
|
hostsClient := hosts.NewClient(md.client)
|
||||||
|
|
||||||
_, err := hostsClient.Read(context.Background(), id)
|
_, 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)
|
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{}) {
|
func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(rolePrincipalIdsKey, raw["principal_ids"])
|
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||||
d.Set(roleGrantStringsKey, raw["grant_strings"])
|
return err
|
||||||
d.Set(roleGrantScopeIdKey, raw["grant_scope_id"])
|
}
|
||||||
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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 {
|
if tcr == nil {
|
||||||
return diag.Errorf("nil role after create")
|
return diag.Errorf("nil role after create")
|
||||||
}
|
}
|
||||||
raw := tcr.GetResponseMap()
|
raw := tcr.GetResponse().Map
|
||||||
|
|
||||||
if principalIds != nil {
|
if principalIds != nil {
|
||||||
tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true))
|
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 {
|
if tspr == nil {
|
||||||
return diag.Errorf("nil role after setting principal IDs")
|
return diag.Errorf("nil role after setting principal IDs")
|
||||||
}
|
}
|
||||||
raw = tspr.GetResponseMap()
|
raw = tspr.GetResponse().Map
|
||||||
}
|
}
|
||||||
|
|
||||||
if grantStrings != nil {
|
if grantStrings != nil {
|
||||||
@@ -170,10 +183,12 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if tsgr == nil {
|
if tsgr == nil {
|
||||||
return diag.Errorf("nil role after setting grant strings")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -184,7 +199,7 @@ func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
|
|
||||||
trr, err := rc.Read(ctx, d.Id())
|
trr, err := rc.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -194,7 +209,9 @@ func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
return diag.Errorf("role nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -247,13 +264,19 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(roleGrantScopeIdKey) {
|
if d.HasChange(roleGrantScopeIdKey) {
|
||||||
d.Set(roleGrantScopeIdKey, grantScopeId)
|
if err := d.Set(roleGrantScopeIdKey, grantScopeId); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(roleGrantStringsKey) {
|
if d.HasChange(roleGrantStringsKey) {
|
||||||
@@ -268,7 +291,9 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("error updating grant strings on role: %v", err)
|
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) {
|
if d.HasChange(rolePrincipalIdsKey) {
|
||||||
@@ -283,7 +308,9 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("error updating grant strings on role: %v", err)
|
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
|
return nil
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ func testAccCheckRoleDestroyed(testProvider *schema.Provider, name string) resou
|
|||||||
rolesClient := roles.NewClient(md.client)
|
rolesClient := roles.NewClient(md.client)
|
||||||
|
|
||||||
_, err := rolesClient.Read(context.Background(), id)
|
_, 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))
|
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)
|
rolesClient := roles.NewClient(md.client)
|
||||||
|
|
||||||
_, err := rolesClient.Read(context.Background(), id)
|
_, 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)
|
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{}) {
|
func setFromScopeResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
if d.Id() == "global" {
|
|
||||||
d.Set(ScopeIdKey, "global")
|
|
||||||
} else {
|
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
|
||||||
}
|
}
|
||||||
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceScopeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -147,7 +159,7 @@ func resourceScopeRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
|||||||
|
|
||||||
srr, err := scp.Read(ctx, d.Id())
|
srr, err := scp.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -157,7 +169,9 @@ func resourceScopeRead(ctx context.Context, d *schema.ResourceData, meta interfa
|
|||||||
return diag.Errorf("scope nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -199,10 +213,14 @@ func resourceScopeUpdate(ctx context.Context, d *schema.ResourceData, meta inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ func testAccCheckScopeResourceDestroy(t *testing.T, testProvider *schema.Provide
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err := scp.Read(context.Background(), id)
|
_, 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)
|
return fmt.Errorf("didn't get a 404 when reading destroyed resource %q: %w", id, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const (
|
|||||||
targetDefaultPortKey = "default_port"
|
targetDefaultPortKey = "default_port"
|
||||||
targetSessionMaxSecondsKey = "session_max_seconds"
|
targetSessionMaxSecondsKey = "session_max_seconds"
|
||||||
targetSessionConnectionLimitKey = "session_connection_limit"
|
targetSessionConnectionLimitKey = "session_connection_limit"
|
||||||
|
targetWorkerFilterKey = "worker_filter"
|
||||||
|
|
||||||
targetTypeTcp = "tcp"
|
targetTypeTcp = "tcp"
|
||||||
)
|
)
|
||||||
@@ -81,18 +82,40 @@ func resourceTarget() *schema.Resource {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
targetWorkerFilterKey: {
|
||||||
|
Description: "Boolean expression to filter the workers for this target",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}) {
|
func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(TypeKey, raw["type"])
|
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||||
d.Set(targetHostSetIdsKey, raw["host_set_ids"])
|
return err
|
||||||
d.Set(targetSessionMaxSecondsKey, raw["session_max_seconds"])
|
}
|
||||||
d.Set(targetSessionConnectionLimitKey, raw["session_connection_limit"])
|
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) {
|
switch raw["type"].(string) {
|
||||||
case targetTypeTcp:
|
case targetTypeTcp:
|
||||||
@@ -100,12 +123,15 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
|
|||||||
attrs := attrsVal.(map[string]interface{})
|
attrs := attrsVal.(map[string]interface{})
|
||||||
if defPort, ok := attrs["default_port"].(json.Number); ok {
|
if defPort, ok := attrs["default_port"].(json.Number); ok {
|
||||||
defPortInt, _ := defPort.Int64()
|
defPortInt, _ := defPort.Int64()
|
||||||
d.Set(targetDefaultPortKey, int(defPortInt))
|
if err := d.Set(targetDefaultPortKey, int(defPortInt)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.SetId(raw["id"].(string))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
@@ -180,6 +206,12 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workerFilterVal, ok := d.GetOk(targetWorkerFilterKey)
|
||||||
|
if ok {
|
||||||
|
workerFilterStr := workerFilterVal.(string)
|
||||||
|
opts = append(opts, targets.WithWorkerFilter(workerFilterStr))
|
||||||
|
}
|
||||||
|
|
||||||
tc := targets.NewClient(md.client)
|
tc := targets.NewClient(md.client)
|
||||||
|
|
||||||
tcr, err := tc.Create(ctx, typeStr, scopeId, opts...)
|
tcr, err := tc.Create(ctx, typeStr, scopeId, opts...)
|
||||||
@@ -189,17 +221,19 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
|
|||||||
if tcr == nil {
|
if tcr == nil {
|
||||||
return diag.Errorf("target nil after create")
|
return diag.Errorf("target nil after create")
|
||||||
}
|
}
|
||||||
raw := tcr.GetResponseMap()
|
raw := tcr.GetResponse().Map
|
||||||
|
|
||||||
if hostSetIds != nil {
|
if hostSetIds != nil {
|
||||||
tur, err := tc.SetHostSets(ctx, tcr.Item.Id, tcr.Item.Version, hostSetIds)
|
tur, err := tc.SetHostSets(ctx, tcr.Item.Id, tcr.Item.Version, hostSetIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("error setting host sets on target: %v", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -210,7 +244,7 @@ func resourceTargetRead(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
|
|
||||||
trr, err := tc.Read(ctx, d.Id())
|
trr, err := tc.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -220,7 +254,9 @@ func resourceTargetRead(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
return diag.Errorf("target nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -295,6 +331,17 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var workerFilter *string
|
||||||
|
if d.HasChange(targetWorkerFilterKey) {
|
||||||
|
opts = append(opts, targets.DefaultWorkerFilter())
|
||||||
|
workerFilterVal, ok := d.GetOk(targetWorkerFilterKey)
|
||||||
|
if ok {
|
||||||
|
workerFilterStr := workerFilterVal.(string)
|
||||||
|
workerFilter = &workerFilterStr
|
||||||
|
opts = append(opts, targets.WithWorkerFilter(workerFilterStr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
opts = append(opts, targets.WithAutomaticVersioning(true))
|
opts = append(opts, targets.WithAutomaticVersioning(true))
|
||||||
_, err := tc.Update(ctx, d.Id(), 0, opts...)
|
_, err := tc.Update(ctx, d.Id(), 0, opts...)
|
||||||
@@ -304,19 +351,34 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(targetDefaultPortKey) {
|
if d.HasChange(targetDefaultPortKey) {
|
||||||
d.Set(targetDefaultPortKey, defaultPort)
|
if err := d.Set(targetDefaultPortKey, defaultPort); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(targetSessionMaxSecondsKey) {
|
if d.HasChange(targetSessionMaxSecondsKey) {
|
||||||
d.Set(targetSessionMaxSecondsKey, sessionMaxSeconds)
|
if err := d.Set(targetSessionMaxSecondsKey, sessionMaxSeconds); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(targetSessionConnectionLimitKey) {
|
if d.HasChange(targetSessionConnectionLimitKey) {
|
||||||
d.Set(targetSessionConnectionLimitKey, sessionConnectionLimit)
|
if err := d.Set(targetSessionConnectionLimitKey, sessionConnectionLimit); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.HasChange(targetWorkerFilterKey) {
|
||||||
|
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
|
// The above call may not actually happen, so we use d.Id() and automatic
|
||||||
@@ -333,7 +395,9 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("error updating host sets in target: %v", err)
|
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
|
return nil
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ resource "boundary_target" "foo" {
|
|||||||
depends_on = [boundary_role.proj1_admin]
|
depends_on = [boundary_role.proj1_admin]
|
||||||
session_max_seconds = 6000
|
session_max_seconds = 6000
|
||||||
session_connection_limit = 6
|
session_connection_limit = 6
|
||||||
|
worker_filter = "type == \"foo\""
|
||||||
}`, fooTargetDescription)
|
}`, fooTargetDescription)
|
||||||
|
|
||||||
fooTargetUpdate = fmt.Sprintf(`
|
fooTargetUpdate = fmt.Sprintf(`
|
||||||
@@ -81,6 +82,7 @@ resource "boundary_target" "foo" {
|
|||||||
depends_on = [boundary_role.proj1_admin]
|
depends_on = [boundary_role.proj1_admin]
|
||||||
session_max_seconds = 7000
|
session_max_seconds = 7000
|
||||||
session_connection_limit = 7
|
session_connection_limit = 7
|
||||||
|
worker_filter = "type == \"bar\""
|
||||||
}`, fooTargetDescriptionUpdate)
|
}`, fooTargetDescriptionUpdate)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,6 +107,7 @@ func TestAccTarget(t *testing.T) {
|
|||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "22"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "22"),
|
||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "6000"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "6000"),
|
||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "6"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "6"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_target.foo", targetWorkerFilterKey, `type == "foo"`),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
importStep("boundary_target.foo"),
|
importStep("boundary_target.foo"),
|
||||||
@@ -117,6 +120,7 @@ func TestAccTarget(t *testing.T) {
|
|||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "80"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetDefaultPortKey, "80"),
|
||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "7000"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionMaxSecondsKey, "7000"),
|
||||||
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "7"),
|
resource.TestCheckResourceAttr("boundary_target.foo", targetSessionConnectionLimitKey, "7"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_target.foo", targetWorkerFilterKey, `type == "bar"`),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
importStep("boundary_target.foo"),
|
importStep("boundary_target.foo"),
|
||||||
@@ -220,7 +224,7 @@ func testAccCheckTargetResourceDestroy(t *testing.T, testProvider *schema.Provid
|
|||||||
id := rs.Primary.ID
|
id := rs.Primary.ID
|
||||||
|
|
||||||
_, err := tgts.Read(context.Background(), 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)
|
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{}) {
|
func setFromUserResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
d.Set(NameKey, raw["name"])
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
d.Set(DescriptionKey, raw["description"])
|
return err
|
||||||
d.Set(ScopeIdKey, raw["scope_id"])
|
}
|
||||||
d.Set(userAccountIDsKey, raw["account_ids"])
|
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))
|
d.SetId(raw["id"].(string))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
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 {
|
if ucr == nil {
|
||||||
return diag.Errorf("user nil after create")
|
return diag.Errorf("user nil after create")
|
||||||
}
|
}
|
||||||
raw := ucr.GetResponseMap()
|
raw := ucr.GetResponse().Map
|
||||||
|
|
||||||
if val, ok := d.GetOk(userAccountIDsKey); ok {
|
if val, ok := d.GetOk(userAccountIDsKey); ok {
|
||||||
list := val.(*schema.Set).List()
|
list := val.(*schema.Set).List()
|
||||||
@@ -112,10 +121,12 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if usrac == nil {
|
if usrac == nil {
|
||||||
return diag.Errorf("user nil after setting accounts")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -126,7 +137,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
|
|
||||||
urr, err := usrs.Read(ctx, d.Id())
|
urr, err := usrs.Read(ctx, d.Id())
|
||||||
if err != nil {
|
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("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -136,7 +147,9 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
|
|||||||
return diag.Errorf("user nil after read")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -178,10 +191,14 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(NameKey) {
|
if d.HasChange(NameKey) {
|
||||||
d.Set(NameKey, name)
|
if err := d.Set(NameKey, name); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(DescriptionKey) {
|
if d.HasChange(DescriptionKey) {
|
||||||
d.Set(DescriptionKey, desc)
|
if err := d.Set(DescriptionKey, desc); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.HasChange(userAccountIDsKey) {
|
if d.HasChange(userAccountIDsKey) {
|
||||||
@@ -197,7 +214,9 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("error updating accounts on user: %v", err)
|
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
|
return nil
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ func testAccCheckUserResourceDestroy(t *testing.T, testProvider *schema.Provider
|
|||||||
usrs := users.NewClient(md.client)
|
usrs := users.NewClient(md.client)
|
||||||
|
|
||||||
_, err := usrs.Read(context.Background(), id)
|
_, 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)
|
return fmt.Errorf("didn't get a 404 when reading destroyed user %q: %v", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user