Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c1c095a66 | ||
|
|
f9fd811205 | ||
|
|
ad43c0bec0 | ||
|
|
5d6d277186 | ||
|
|
4590e7f8c8 | ||
|
|
47c3f92f5c | ||
|
|
490476a5e5 | ||
|
|
a256b763ae | ||
|
|
f6539b969c | ||
|
|
695e28a38b | ||
|
|
b7b11dd817 | ||
|
|
b9bc73d4cf | ||
|
|
e847f5fde7 | ||
|
|
53c2a5769c | ||
|
|
ed1bf21505 | ||
|
|
6a23fc20f9 | ||
|
|
41653b2ccd | ||
|
|
398eaf8406 | ||
|
|
c71ba43a3d | ||
|
|
1153ea44ee | ||
|
|
2020819648 | ||
|
|
b7eadd565f | ||
|
|
7e7707d3af | ||
|
|
8c12b27f8f | ||
|
|
93e41ae83d | ||
|
|
bbc5889404 | ||
|
|
933192280b |
No files matched your search
@@ -8,7 +8,7 @@ jobs:
|
|||||||
actionlint:
|
actionlint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
- name: Check workflow files
|
- name: Check workflow files
|
||||||
uses: docker://docker.mirror.hashicorp.services/rhysd/actionlint@sha256:02ccb6d91e4cb4a7b21eb99d5274d257e81ae667688d730e89d7ea0d6d35db91
|
uses: docker://docker.mirror.hashicorp.services/rhysd/actionlint@sha256:02ccb6d91e4cb4a7b21eb99d5274d257e81ae667688d730e89d7ea0d6d35db91
|
||||||
with:
|
with:
|
||||||
|
|||||||
+39
-20
@@ -22,7 +22,7 @@ jobs:
|
|||||||
id: boundary-team-role
|
id: boundary-team-role
|
||||||
run: |
|
run: |
|
||||||
TEAM="boundary"
|
TEAM="boundary"
|
||||||
ROLE="$(hub api orgs/hashicorp/teams/${TEAM}/memberships/${{ github.actor }} | jq -r '.role | select(.!=null)')"
|
ROLE="$(gh api orgs/hashicorp/teams/${TEAM}/memberships/${{ github.actor }} | jq -r '.role | select(.!=null)')"
|
||||||
if [[ -n "${ROLE}" ]]; then
|
if [[ -n "${ROLE}" ]]; then
|
||||||
echo "Actor ${{ github.actor }} is a ${TEAM} team member, skipping ticket creation"
|
echo "Actor ${{ github.actor }} is a ${TEAM} team member, skipping ticket creation"
|
||||||
else
|
else
|
||||||
@@ -32,13 +32,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.JIRA_SYNC_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.JIRA_SYNC_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login
|
|
||||||
uses: atlassian/gajira-login@45fd029b9f1d6d8926c6f04175aa80c0e42c9026 # v3.0.1
|
|
||||||
env:
|
|
||||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
|
||||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
|
||||||
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set ticket type
|
- name: Set ticket type
|
||||||
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
||||||
id: set-ticket-type
|
id: set-ticket-type
|
||||||
@@ -52,6 +45,10 @@ jobs:
|
|||||||
- name: Create ticket
|
- name: Create ticket
|
||||||
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
||||||
uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1
|
uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1
|
||||||
|
env:
|
||||||
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
with:
|
with:
|
||||||
project: ICU
|
project: ICU
|
||||||
issuetype: "GH Issue"
|
issuetype: "GH Issue"
|
||||||
@@ -64,6 +61,10 @@ jobs:
|
|||||||
if: github.event.action != 'opened'
|
if: github.event.action != 'opened'
|
||||||
id: search
|
id: search
|
||||||
uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
|
uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
|
||||||
|
env:
|
||||||
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
with:
|
with:
|
||||||
# cf[10089] is Issue Link custom field
|
# cf[10089] is Issue Link custom field
|
||||||
jql: 'issuetype = "GH Issue" and cf[10089]="${{ github.event.issue.html_url || github.event.pull_request.html_url }}"'
|
jql: 'issuetype = "GH Issue" and cf[10089]="${{ github.event.issue.html_url || github.event.pull_request.html_url }}"'
|
||||||
@@ -71,20 +72,38 @@ jobs:
|
|||||||
- name: Sync comment
|
- name: Sync comment
|
||||||
if: github.event.action == 'created' && steps.search.outputs.issue
|
if: github.event.action == 'created' && steps.search.outputs.issue
|
||||||
uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0
|
uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0
|
||||||
|
env:
|
||||||
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
with:
|
with:
|
||||||
issue: ${{ steps.search.outputs.issue }}
|
issue: ${{ steps.search.outputs.issue }}
|
||||||
comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}"
|
comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}"
|
||||||
|
|
||||||
- name: Close ticket
|
- name: Transitions
|
||||||
if: (github.event.action == 'closed' || github.event.action == 'deleted') && steps.search.outputs.issue
|
id: transitions
|
||||||
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3.0.1
|
if: steps.search.outputs.issue
|
||||||
with:
|
run: |
|
||||||
issue: ${{ steps.search.outputs.issue }}
|
if [[ "${{ github.event.action }}" == "closed" || "${{ github.event.action }}" == "deleted" ]]; then
|
||||||
transition: Done
|
echo "Closing ticket"
|
||||||
|
echo "name=Done" >> "$GITHUB_OUTPUT"
|
||||||
|
elif [[ "${{ github.event.action }}" == "reopened" ]]; then
|
||||||
|
echo "Reopening ticket"
|
||||||
|
echo "name='Reopen'" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Reopen ticket
|
# Transition issue API reference: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post
|
||||||
if: github.event.action == 'reopened' && steps.search.outputs.issue
|
- name: Transition ticket
|
||||||
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3.0.1
|
if: steps.transitions.outputs.name
|
||||||
with:
|
run: |
|
||||||
issue: ${{ steps.search.outputs.issue }}
|
transitions="$(curl --silent \
|
||||||
transition: "To Do"
|
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
|
||||||
|
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
|
||||||
|
--header "Accept: application/json")"
|
||||||
|
id="$(echo "${transitions}" | jq -r '.transitions[] | select(.name == "${{ steps.transitions.outputs.name }}") | .id')"
|
||||||
|
curl --silent \
|
||||||
|
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
|
||||||
|
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
|
||||||
|
--header "Accept: application/json" \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--data "$(printf '{"transition": {"id": "%s"}}' "${id}")"
|
||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
name: "Check for uncommitted changes from make gen"
|
name: "Check for uncommitted changes from make gen"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
with:
|
with:
|
||||||
fetch-depth: '0'
|
fetch-depth: '0'
|
||||||
- name: Determine Go version
|
- name: Determine Go version
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
echo "Building with Go $(cat .go-version)"
|
echo "Building with Go $(cat .go-version)"
|
||||||
echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT"
|
echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT"
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||||
with:
|
with:
|
||||||
go-version: "${{ steps.get-go-version.outputs.go-version }}"
|
go-version: "${{ steps.get-go-version.outputs.go-version }}"
|
||||||
- name: Running go mod tidy
|
- name: Running go mod tidy
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.go-version.outputs.go-version }}
|
version: ${{ steps.go-version.outputs.go-version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
- id: go-version
|
- id: go-version
|
||||||
# We use .go-version as our source of truth for current Go
|
# We use .go-version as our source of truth for current Go
|
||||||
# version, because "goenv" can react to it automatically.
|
# version, because "goenv" can react to it automatically.
|
||||||
@@ -24,12 +24,12 @@ jobs:
|
|||||||
release-notes:
|
release-notes:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Generate Release Notes
|
- name: Generate Release Notes
|
||||||
run: sed -n -e "1{/# /d;}" -e "2{/^$/d;}" -e "/# $(git describe --abbrev=0 --exclude="$(git describe --abbrev=0 --match='v*.*.*' --tags)" --match='v*.*.*' --tags | tr -d v)/q;p" CHANGELOG.md > release-notes.txt
|
run: sed -n -e "1{/# /d;}" -e "2{/^$/d;}" -e "/# $(git describe --abbrev=0 --exclude="$(git describe --abbrev=0 --match='v*.*.*' --tags)" --match='v*.*.*' --tags | tr -d v)/q;p" CHANGELOG.md > release-notes.txt
|
||||||
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
- uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||||
with:
|
with:
|
||||||
name: release-notes
|
name: release-notes
|
||||||
path: release-notes.txt
|
path: release-notes.txt
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
terraform-provider-release:
|
terraform-provider-release:
|
||||||
name: 'Terraform Provider Release'
|
name: 'Terraform Provider Release'
|
||||||
needs: [go-version, release-notes]
|
needs: [go-version, release-notes]
|
||||||
uses: hashicorp/ghaction-terraform-provider-release/.github/workflows/hashicorp.yml@v3
|
uses: hashicorp/ghaction-terraform-provider-release/.github/workflows/hashicorp.yml@v4
|
||||||
secrets:
|
secrets:
|
||||||
hc-releases-github-token: '${{ secrets.HASHI_RELEASES_GITHUB_TOKEN }}'
|
hc-releases-github-token: '${{ secrets.HASHI_RELEASES_GITHUB_TOKEN }}'
|
||||||
hc-releases-host-staging: '${{ secrets.HC_RELEASES_HOST_STAGING }}'
|
hc-releases-host-staging: '${{ secrets.HC_RELEASES_HOST_STAGING }}'
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
- name: Determine go version
|
- name: Determine go version
|
||||||
id: get-go-version
|
id: get-go-version
|
||||||
# We use .go-version as our source of truth for current Go
|
# We use .go-version as our source of truth for current Go
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
echo "Building with Go $(cat .go-version)"
|
echo "Building with Go $(cat .go-version)"
|
||||||
echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT"
|
echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT"
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||||
with:
|
with:
|
||||||
go-version: "${{ steps.get-go-version.outputs.go-version }}"
|
go-version: "${{ steps.get-go-version.outputs.go-version }}"
|
||||||
cache: false
|
cache: false
|
||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
|
echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
|
||||||
echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
||||||
- name: Set up Go modules cache
|
- name: Set up Go modules cache
|
||||||
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
${{ steps.go-cache-paths.outputs.go-build }}
|
${{ steps.go-cache-paths.outputs.go-build }}
|
||||||
|
|||||||
+34
-2
@@ -2,11 +2,43 @@
|
|||||||
|
|
||||||
Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider.
|
Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider.
|
||||||
|
|
||||||
|
## 1.2.0 (October 21, 2024)
|
||||||
|
|
||||||
|
### New and Improved
|
||||||
|
|
||||||
|
* Introduces support for specifying a worker filter in dynamic host catalogs
|
||||||
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/626))
|
||||||
|
|
||||||
|
### Deprecations/Changes
|
||||||
|
|
||||||
|
* With Boundary 0.15, a deprecation notice was put under the `grant_scope_id`
|
||||||
|
field, and a new `grant_scope_ids` field was introduced to replace it. With
|
||||||
|
Boundary v0.17.1 and Boundary API v0.0.52, `grant_scope_id` support was
|
||||||
|
entirely removed. `grant_scope_id` support has now been removed from this TF
|
||||||
|
provider.
|
||||||
|
|
||||||
|
## 1.1.15 (May 1, 2024)
|
||||||
|
|
||||||
|
### New and Improved
|
||||||
|
|
||||||
|
* Add support for a target alias as a resource
|
||||||
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/571))
|
||||||
|
|
||||||
|
## 1.1.14 (February 14, 2024)
|
||||||
|
|
||||||
|
### New and Improved
|
||||||
|
|
||||||
|
* Support the multi-value `grant_scope_ids` field in the role provider
|
||||||
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/562))
|
||||||
|
|
||||||
|
* Support Boundary [Storage Policies](https://developer.hashicorp.com/boundary/docs/configuration/session-recording/configure-storage-policy)
|
||||||
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/558))
|
||||||
|
|
||||||
## 1.1.13 (February 1, 2024)
|
## 1.1.13 (February 1, 2024)
|
||||||
|
|
||||||
### New and Improved
|
### New and Improved
|
||||||
|
|
||||||
* Allow dynamic credentials when configuring storage buckets.
|
* Allow dynamic credentials when configuring storage buckets
|
||||||
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/549))
|
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/549))
|
||||||
|
|
||||||
## 1.1.12 (January 8, 2024)
|
## 1.1.12 (January 8, 2024)
|
||||||
@@ -318,4 +350,4 @@ Update provider to handle new domain errors ([PR](https://github.com/hashicorp/t
|
|||||||
|
|
||||||
## 0.1.0 (October 14, 2020)
|
## 0.1.0 (October 14, 2020)
|
||||||
|
|
||||||
Initial release!
|
Initial release!
|
||||||
@@ -97,10 +97,10 @@ Please see our detailed docs for individual resource usage. Below is a complex e
|
|||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
auth_method_id = "ampw_1234567890" # changeme
|
auth_method_id = "ampw_1234567890" # changeme
|
||||||
password_auth_method_login_name = "myuser" # changeme
|
auth_method_login_name = "myuser" # changeme
|
||||||
password_auth_method_password = "passpass" # changeme
|
auth_method_password = "passpass" # changeme
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "users" {
|
variable "users" {
|
||||||
|
|||||||
+11
-11
@@ -15,23 +15,23 @@ Do not keep your authentication password in HCL for production environments, use
|
|||||||
|
|
||||||
```terraform
|
```terraform
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
auth_method_id = "ampw_1234567890" # changeme
|
auth_method_id = "ampw_1234567890" # changeme
|
||||||
password_auth_method_login_name = "myuser" # changeme
|
auth_method_login_name = "myuser" # changeme
|
||||||
password_auth_method_password = "passpass" # changeme
|
auth_method_password = "passpass" # changeme
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
password_auth_method_login_name = "myuser"
|
auth_method_login_name = "myuser"
|
||||||
password_auth_method_password = "passpass"
|
auth_method_password = "passpass"
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
password_auth_method_login_name = "myuser"
|
auth_method_login_name = "myuser"
|
||||||
password_auth_method_password = "passpass"
|
auth_method_password = "passpass"
|
||||||
scope_id = "s_1234567890"
|
scope_id = "s_1234567890"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||||
|
page_title: "boundary_alias_target Resource - terraform-provider-boundary"
|
||||||
|
subcategory: ""
|
||||||
|
description: |-
|
||||||
|
The target alias resource allows you to configure a Boundary target alias.
|
||||||
|
---
|
||||||
|
|
||||||
|
# boundary_alias_target (Resource)
|
||||||
|
|
||||||
|
The target alias resource allows you to configure a Boundary target alias.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
resource "boundary_scope" "org" {
|
||||||
|
name = "organization_one"
|
||||||
|
description = "global scope"
|
||||||
|
scope_id = "global"
|
||||||
|
auto_create_admin_role = true
|
||||||
|
auto_create_default_role = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_scope" "project" {
|
||||||
|
name = "project_one"
|
||||||
|
description = "My first scope!"
|
||||||
|
scope_id = boundary_scope.org.id
|
||||||
|
auto_create_admin_role = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_catalog_static" "foo" {
|
||||||
|
name = "test"
|
||||||
|
description = "test catalog"
|
||||||
|
scope_id = boundary_scope.project.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_static" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
address = "10.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_static" "bar" {
|
||||||
|
name = "bar"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
address = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_set_static" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
|
||||||
|
host_ids = [
|
||||||
|
boundary_host_static.foo.id,
|
||||||
|
boundary_host_static.bar.id,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_target" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
description = "Foo target"
|
||||||
|
type = "tcp"
|
||||||
|
default_port = "22"
|
||||||
|
scope_id = boundary_scope.project.id
|
||||||
|
host_source_ids = [
|
||||||
|
boundary_host_set_static.foo.id,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_alias_target" "example_alias_target" {
|
||||||
|
name = "example_alias_target"
|
||||||
|
description = "Example alias to target foo using host boundary_host_static.bar"
|
||||||
|
scope_id = "global"
|
||||||
|
value = "example.bar.foo.boundary"
|
||||||
|
destination_id = boundary_target.foo.id
|
||||||
|
authorize_session_host_id = boundary_host_static.bar.id
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `scope_id` (String) The scope ID.
|
||||||
|
- `value` (String) The value of the alias.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
- `authorize_session_host_id` (String) The host id to pass to Boundary when performing an authorize session action.
|
||||||
|
- `description` (String) The alias description.
|
||||||
|
- `destination_id` (String) The destination of the alias.
|
||||||
|
- `name` (String) The alias name. Defaults to the resource name.
|
||||||
|
- `type` (String) The type of alias; hardcoded.
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `id` (String) The ID of the account.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Import is supported using the following syntax:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
terraform import boundary_alias_target.example_alias_target <my-id>
|
||||||
|
```
|
||||||
@@ -94,6 +94,7 @@ resource "boundary_host_catalog_plugin" "azure_example" {
|
|||||||
- `plugin_name` (String) The name of the plugin that should back the resource. This or plugin_id must be defined.
|
- `plugin_name` (String) The name of the plugin that should back the resource. This or plugin_id must be defined.
|
||||||
- `secrets_hmac` (String) The HMAC'd secrets value returned from the server.
|
- `secrets_hmac` (String) The HMAC'd secrets value returned from the server.
|
||||||
- `secrets_json` (String, Sensitive) The secrets for the host catalog. Either values encoded with the "jsonencode" function, pre-escaped JSON string, or a file:// or env:// path. Set to a string "null" to clear any existing values. NOTE: Unlike "attributes_json", removing this block will NOT clear secrets from the host catalog; this allows injecting secrets for one call, then removing them for storage.
|
- `secrets_json` (String, Sensitive) The secrets for the host catalog. Either values encoded with the "jsonencode" function, pre-escaped JSON string, or a file:// or env:// path. Set to a string "null" to clear any existing values. NOTE: Unlike "attributes_json", removing this block will NOT clear secrets from the host catalog; this allows injecting secrets for one call, then removing them for storage.
|
||||||
|
- `worker_filter` (String) HCP Only. A filter used to control which PKI workers can handle dynamic host catalog requests.
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||||
|
page_title: "boundary_policy_storage Resource - terraform-provider-boundary"
|
||||||
|
subcategory: ""
|
||||||
|
description: |-
|
||||||
|
The storage policy resource allows you to configure a Boundary storage policy. Storage policies allow an admin to configure how long session recordings must be stored and when to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.
|
||||||
|
---
|
||||||
|
|
||||||
|
# boundary_policy_storage (Resource)
|
||||||
|
|
||||||
|
The storage policy resource allows you to configure a Boundary storage policy. Storage policies allow an admin to configure how long session recordings must be stored and when to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `scope_id` (String) The scope for this policy.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
- `delete_after_days` (Number) The number of days after which a session recording will be automatically deleted. Defaults to 0: never automatically delete. However, delete_after_days and retain_for_days cannot both be 0.
|
||||||
|
- `delete_after_overridable` (Boolean) Whether or not the associated delete_after_days value can be overridden by org scopes. Note: if the associated delete_after_days value is 0, overridable is ignored
|
||||||
|
- `description` (String) The policy description.
|
||||||
|
- `name` (String) The policy name. Defaults to the resource name.
|
||||||
|
- `retain_for_days` (Number) The number of days a session recording is required to be stored. Defaults to 0: allow deletions at any time. However, retain_for_days and delete_after_days cannot both be 0.
|
||||||
|
- `retain_for_overridable` (Boolean) Whether or not the associated retain_for_days value can be overridden by org scopes. Note: if the associated retain_for_days value is 0, overridable is ignored.
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `id` (String) The ID of the policy.
|
||||||
@@ -127,7 +127,7 @@ resource "boundary_role" "readonly" {
|
|||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- `description` (String) The role description.
|
- `description` (String) The role description.
|
||||||
- `grant_scope_id` (String)
|
- `grant_scope_ids` (Set of String) A list of scopes for which the grants in this role should apply, which can include the special values "this", "children", or "descendants"
|
||||||
- `grant_strings` (Set of String) A list of stringified grants for the role.
|
- `grant_strings` (Set of String) A list of stringified grants for the role.
|
||||||
- `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.
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ resource "boundary_scope" "org" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "boundary_role" "org_admin" {
|
resource "boundary_role" "org_admin" {
|
||||||
scope_id = boundary_scope.global.id
|
scope_id = boundary_scope.global.id
|
||||||
grant_scope_id = boundary_scope.org.id
|
grant_scope_ids = [boundary_scope.org.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||||
|
page_title: "boundary_scope_policy_attachment Resource - terraform-provider-boundary"
|
||||||
|
subcategory: ""
|
||||||
|
description: |-
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# boundary_scope_policy_attachment (Resource)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `policy_id` (String)
|
||||||
|
- `scope_id` (String)
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `id` (String) The ID of this resource.
|
||||||
@@ -48,8 +48,9 @@ resource "boundary_storage_bucket" "aws_dynamic_credentials_example" {
|
|||||||
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
|
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
|
||||||
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
|
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
|
||||||
attributes_json = jsonencode({
|
attributes_json = jsonencode({
|
||||||
"region" = "us-east-1"
|
"region" = "us-east-1"
|
||||||
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
|
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
|
||||||
|
"disable_credential_rotation" = "true"
|
||||||
})
|
})
|
||||||
worker_filter = "\"pki\" in \"/tags/type\""
|
worker_filter = "\"pki\" in \"/tags/type\""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "boundary_worker Resource - terraform-provider-boundary"
|
page_title: "boundary_worker Resource - terraform-provider-boundary"
|
||||||
subcategory: ""
|
subcategory: ""
|
||||||
description: |-
|
description: |-
|
||||||
@@ -12,16 +11,22 @@ The resource allows you to create a self-managed worker object.
|
|||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
### Controller-led worker
|
||||||
|
|
||||||
```terraform
|
```terraform
|
||||||
resource "boundary_worker" "controller_led" {
|
resource "boundary_worker" "controller_led" {
|
||||||
scope_id = "global"
|
scope_id = "global"
|
||||||
name = "worker 1"
|
name = "controller-led-worker-1"
|
||||||
description = "self managed worker with controller led auth"
|
description = "self managed worker with controller led auth"
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Worker-led worker
|
||||||
|
|
||||||
|
```terraform
|
||||||
resource "boundary_worker" "worker_led" {
|
resource "boundary_worker" "worker_led" {
|
||||||
scope_id = "global"
|
scope_id = "global"
|
||||||
name = "worker 2"
|
name = "worker-led-worker-1"
|
||||||
description = "self managed worker with worker led auth"
|
description = "self managed worker with worker led auth"
|
||||||
worker_generated_auth_token = var.worker_generated_auth_token
|
worker_generated_auth_token = var.worker_generated_auth_token
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
auth_method_id = "ampw_1234567890" # changeme
|
auth_method_id = "ampw_1234567890" # changeme
|
||||||
password_auth_method_login_name = "myuser" # changeme
|
auth_method_login_name = "myuser" # changeme
|
||||||
password_auth_method_password = "passpass" # changeme
|
auth_method_password = "passpass" # changeme
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
password_auth_method_login_name = "myuser"
|
auth_method_login_name = "myuser"
|
||||||
password_auth_method_password = "passpass"
|
auth_method_password = "passpass"
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "http://127.0.0.1:9200"
|
addr = "http://127.0.0.1:9200"
|
||||||
password_auth_method_login_name = "myuser"
|
auth_method_login_name = "myuser"
|
||||||
password_auth_method_password = "passpass"
|
auth_method_password = "passpass"
|
||||||
scope_id = "s_1234567890"
|
scope_id = "s_1234567890"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
terraform import boundary_alias_target.example_alias_target <my-id>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
resource "boundary_scope" "org" {
|
||||||
|
name = "organization_one"
|
||||||
|
description = "global scope"
|
||||||
|
scope_id = "global"
|
||||||
|
auto_create_admin_role = true
|
||||||
|
auto_create_default_role = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_scope" "project" {
|
||||||
|
name = "project_one"
|
||||||
|
description = "My first scope!"
|
||||||
|
scope_id = boundary_scope.org.id
|
||||||
|
auto_create_admin_role = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_catalog_static" "foo" {
|
||||||
|
name = "test"
|
||||||
|
description = "test catalog"
|
||||||
|
scope_id = boundary_scope.project.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_static" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
address = "10.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_static" "bar" {
|
||||||
|
name = "bar"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
address = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_host_set_static" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
host_catalog_id = boundary_host_catalog_static.foo.id
|
||||||
|
|
||||||
|
host_ids = [
|
||||||
|
boundary_host_static.foo.id,
|
||||||
|
boundary_host_static.bar.id,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_target" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
description = "Foo target"
|
||||||
|
type = "tcp"
|
||||||
|
default_port = "22"
|
||||||
|
scope_id = boundary_scope.project.id
|
||||||
|
host_source_ids = [
|
||||||
|
boundary_host_set_static.foo.id,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_alias_target" "example_alias_target" {
|
||||||
|
name = "example_alias_target"
|
||||||
|
description = "Example alias to target foo using host boundary_host_static.bar"
|
||||||
|
scope_id = "global"
|
||||||
|
value = "example.bar.foo.boundary"
|
||||||
|
destination_id = boundary_target.foo.id
|
||||||
|
authorize_session_host_id = boundary_host_static.bar.id
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
resource "boundary_scope" "global" {
|
||||||
|
global_scope = true
|
||||||
|
scope_id = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_scope" "org" {
|
||||||
|
name = "organization_one"
|
||||||
|
description = "My first scope!"
|
||||||
|
scope_id = boundary_scope.global.id
|
||||||
|
auto_create_admin_role = true
|
||||||
|
auto_create_default_role = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_policy_storage" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
description = "Foo policy"
|
||||||
|
scope_id = boundary_scope.org.id
|
||||||
|
retain_for_days = 10
|
||||||
|
retain_for_overridable = false
|
||||||
|
delete_after_days = 10
|
||||||
|
delete_after_overridable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "boundary_scope_policy_attachment" "foo_attachment" {
|
||||||
|
scope_id = boundary_scope.org.id
|
||||||
|
policy_id = boundary_policy_storage.foo.id
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@ resource "boundary_scope" "org" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "boundary_role" "org_admin" {
|
resource "boundary_role" "org_admin" {
|
||||||
scope_id = boundary_scope.global.id
|
scope_id = boundary_scope.global.id
|
||||||
grant_scope_id = boundary_scope.org.id
|
grant_scope_ids = [boundary_scope.org.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
@@ -33,8 +33,9 @@ resource "boundary_storage_bucket" "aws_dynamic_credentials_example" {
|
|||||||
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
|
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
|
||||||
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
|
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
|
||||||
attributes_json = jsonencode({
|
attributes_json = jsonencode({
|
||||||
"region" = "us-east-1"
|
"region" = "us-east-1"
|
||||||
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
|
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
|
||||||
|
"disable_credential_rotation" = "true"
|
||||||
})
|
})
|
||||||
worker_filter = "\"pki\" in \"/tags/type\""
|
worker_filter = "\"pki\" in \"/tags/type\""
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
resource "boundary_worker" "controller_led" {
|
||||||
|
scope_id = "global"
|
||||||
|
name = "controller-led-worker-1"
|
||||||
|
description = "self managed worker with controller led auth"
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
resource "boundary_worker" "controller_led" {
|
|
||||||
scope_id = "global"
|
|
||||||
name = "worker 1"
|
|
||||||
description = "self managed worker with controller-led auth"
|
|
||||||
worker_generated_auth_token = var.worker_generated_auth_token
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "boundary_worker" "worker_led" {
|
|
||||||
scope_id = "global"
|
|
||||||
name = "worker 2"
|
|
||||||
description = "self managed worker with worker-led auth"
|
|
||||||
worker_generated_auth_token = var.worker_generated_auth_token
|
|
||||||
}
|
|
||||||
+1
-7
@@ -1,12 +1,6 @@
|
|||||||
resource "boundary_worker" "controller_led" {
|
|
||||||
scope_id = "global"
|
|
||||||
name = "worker 1"
|
|
||||||
description = "self managed worker with controller led auth"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "boundary_worker" "worker_led" {
|
resource "boundary_worker" "worker_led" {
|
||||||
scope_id = "global"
|
scope_id = "global"
|
||||||
name = "worker 2"
|
name = "worker-led-worker-1"
|
||||||
description = "self managed worker with worker led auth"
|
description = "self managed worker with worker led auth"
|
||||||
worker_generated_auth_token = var.worker_generated_auth_token
|
worker_generated_auth_token = var.worker_generated_auth_token
|
||||||
}
|
}
|
||||||
@@ -1,94 +1,95 @@
|
|||||||
module github.com/hashicorp/terraform-provider-boundary
|
module github.com/hashicorp/terraform-provider-boundary
|
||||||
|
|
||||||
go 1.21.5
|
go 1.23.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/YakDriver/regexache v0.23.0
|
github.com/YakDriver/regexache v0.23.0
|
||||||
github.com/hashicorp/boundary v0.15.0
|
github.com/hashicorp/boundary v0.18.0
|
||||||
github.com/hashicorp/boundary/api v0.0.45
|
github.com/hashicorp/boundary/api v0.0.53
|
||||||
github.com/hashicorp/boundary/sdk v0.0.42
|
github.com/hashicorp/boundary/sdk v0.0.49
|
||||||
github.com/hashicorp/cap v0.4.1
|
github.com/hashicorp/cap v0.5.1-0.20240315182732-faa330bfb8df
|
||||||
github.com/hashicorp/cap/ldap v0.0.0-20231012003312-273118a6e3b8
|
github.com/hashicorp/cap/ldap v0.0.0-20240206183135-ed8f24513744
|
||||||
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
|
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
|
||||||
github.com/hashicorp/go-kms-wrapping/v2 v2.0.15
|
github.com/hashicorp/go-kms-wrapping/v2 v2.0.17-0.20240313190905-91d44aa8e360
|
||||||
github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11
|
github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11
|
||||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8
|
||||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6
|
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.18.0
|
github.com/hashicorp/terraform-plugin-docs v0.18.0
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0
|
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
|
||||||
github.com/jimlambrt/gldap v0.1.9
|
github.com/jimlambrt/gldap v0.1.11
|
||||||
github.com/kr/pretty v0.3.1
|
github.com/kr/pretty v0.3.1
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/crypto v0.18.0
|
golang.org/x/crypto v0.25.0
|
||||||
mvdan.cc/gofumpt v0.5.0
|
mvdan.cc/gofumpt v0.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
|
github.com/DATA-DOG/go-sqlmock v1.5.2 // indirect
|
||||||
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
|
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
github.com/ProtonMail/go-crypto v1.1.0-alpha.0 // indirect
|
||||||
github.com/agext/levenshtein v1.2.2 // indirect
|
github.com/agext/levenshtein v1.2.2 // indirect
|
||||||
github.com/alessio/shellescape v1.4.1 // indirect
|
github.com/alessio/shellescape v1.4.2 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||||
github.com/armon/go-radix v1.0.0 // indirect
|
github.com/armon/go-radix v1.0.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||||
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
|
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.7 // indirect
|
github.com/cloudflare/circl v1.3.7 // indirect
|
||||||
github.com/containerd/continuity v0.3.0 // indirect
|
github.com/containerd/continuity v0.4.3 // indirect
|
||||||
github.com/coreos/go-oidc/v3 v3.8.0 // indirect
|
github.com/coreos/go-oidc/v3 v3.9.0 // indirect
|
||||||
github.com/danieljoos/wincred v1.2.0 // indirect
|
github.com/danieljoos/wincred v1.2.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/cli v23.0.1+incompatible // indirect
|
github.com/docker/cli v25.0.3+incompatible // indirect
|
||||||
github.com/docker/docker v24.0.7+incompatible // indirect
|
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/dvsekhvalnov/jose2go v1.5.1-0.20231206184617-48ba0b76bc88 // indirect
|
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
|
||||||
github.com/fatih/color v1.16.0 // indirect
|
github.com/fatih/color v1.17.0 // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||||
github.com/glebarez/sqlite v1.9.0 // indirect
|
github.com/glebarez/sqlite v1.10.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||||
github.com/go-ldap/ldap/v3 v3.4.6 // indirect
|
github.com/go-ldap/ldap/v3 v3.4.6 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-migrate/migrate/v4 v4.16.2 // indirect
|
github.com/golang-migrate/migrate/v4 v4.17.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/google/uuid v1.4.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
|
||||||
github.com/hashicorp/cli v1.1.6 // indirect
|
github.com/hashicorp/cli v1.1.6 // indirect
|
||||||
github.com/hashicorp/dbassert v0.0.0-20231012105025-1bc1bd88e22b // indirect
|
github.com/hashicorp/dbassert v0.0.0-20231012105025-1bc1bd88e22b // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 // indirect
|
github.com/hashicorp/eventlogger v0.2.9 // indirect
|
||||||
github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 // indirect
|
github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231208142215-efdb51ec090d // indirect
|
||||||
github.com/hashicorp/go-bexpr v0.1.13 // indirect
|
github.com/hashicorp/go-bexpr v0.1.13 // indirect
|
||||||
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-dbw v0.1.1 // indirect
|
github.com/hashicorp/go-dbw v0.1.5-0.20240909162114-6cee92b3da36 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||||
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20231124110655-4315424d22d0 // indirect
|
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20231219183231-6bac757bb482 // indirect
|
||||||
github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 // indirect
|
github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.6.0 // indirect
|
github.com/hashicorp/go-plugin v1.6.0 // indirect
|
||||||
github.com/hashicorp/go-rate v0.0.0-20231204194614-cc8d401f70ab // indirect
|
github.com/hashicorp/go-rate v0.0.0-20231204194614-cc8d401f70ab // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect
|
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect
|
||||||
github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1 // indirect
|
github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1 // indirect
|
||||||
@@ -98,34 +99,33 @@ require (
|
|||||||
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 // indirect
|
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 // indirect
|
||||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 // indirect
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 // indirect
|
||||||
github.com/hashicorp/go-sockaddr v1.0.5 // indirect
|
github.com/hashicorp/go-sockaddr v1.0.6 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||||
github.com/hashicorp/hc-install v0.6.2 // indirect
|
github.com/hashicorp/hc-install v0.6.3 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||||
github.com/hashicorp/hcl/v2 v2.19.1 // indirect
|
github.com/hashicorp/hcl/v2 v2.19.1 // indirect
|
||||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||||
github.com/hashicorp/nodeenrollment v0.2.9 // indirect
|
github.com/hashicorp/nodeenrollment v0.2.13 // indirect
|
||||||
github.com/hashicorp/terraform-exec v0.20.0 // indirect
|
github.com/hashicorp/terraform-exec v0.20.0 // indirect
|
||||||
github.com/hashicorp/terraform-json v0.21.0 // indirect
|
github.com/hashicorp/terraform-json v0.21.0 // indirect
|
||||||
github.com/hashicorp/terraform-plugin-go v0.20.0 // indirect
|
github.com/hashicorp/terraform-plugin-go v0.22.0 // indirect
|
||||||
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
|
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
|
||||||
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
|
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
|
||||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
||||||
github.com/hashicorp/vault/api v1.10.0 // indirect
|
github.com/hashicorp/vault/api v1.12.0 // indirect
|
||||||
github.com/hashicorp/vault/sdk v0.3.0 // indirect
|
github.com/hashicorp/vault/sdk v0.11.0 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||||
github.com/huandu/xstrings v1.4.0 // indirect
|
github.com/huandu/xstrings v1.4.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.15 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||||
github.com/jackc/pgconn v1.14.1 // indirect
|
github.com/jackc/pgconn v1.14.3 // indirect
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
github.com/jackc/pgio v1.0.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
github.com/jackc/pgtype v1.14.0 // indirect
|
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||||
github.com/jackc/pgx/v4 v4.18.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
|
||||||
github.com/jefferai/go-libsecret v0.0.0-20210525195240-b53481abef97 // indirect
|
github.com/jefferai/go-libsecret v0.0.0-20210525195240-b53481abef97 // indirect
|
||||||
github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f // indirect
|
github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f // indirect
|
||||||
github.com/jefferai/keyring v1.1.7-0.20220316160357-58a74bb55891 // indirect
|
github.com/jefferai/keyring v1.1.7-0.20220316160357-58a74bb55891 // indirect
|
||||||
@@ -138,7 +138,6 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
|
||||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
|
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
|
||||||
github.com/mitchellh/cli v1.1.5 // indirect
|
github.com/mitchellh/cli v1.1.5 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
@@ -147,65 +146,68 @@ require (
|
|||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/pointerstructure v1.2.1 // indirect
|
github.com/mitchellh/pointerstructure v1.2.1 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/sys/user v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.0 // indirect
|
github.com/moby/term v0.5.0 // indirect
|
||||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||||
github.com/mtibben/percent v0.2.1 // indirect
|
github.com/mtibben/percent v0.2.1 // indirect
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
|
||||||
github.com/opencontainers/runc v1.1.12 // indirect
|
github.com/opencontainers/runc v1.2.0-rc.3 // indirect
|
||||||
github.com/ory/dockertest/v3 v3.10.0 // indirect
|
github.com/ory/dockertest/v3 v3.10.0 // indirect
|
||||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/posener/complete v1.2.3 // indirect
|
github.com/posener/complete v1.2.3 // indirect
|
||||||
github.com/prometheus/client_golang v1.17.0 // indirect
|
github.com/prometheus/client_golang v1.18.0 // indirect
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/common v0.46.0 // indirect
|
||||||
github.com/prometheus/procfs v0.11.1 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||||
github.com/russross/blackfriday v1.6.0 // indirect
|
github.com/russross/blackfriday v1.6.0 // indirect
|
||||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||||
github.com/sethvargo/go-diceware v0.3.0 // indirect
|
github.com/sethvargo/go-diceware v0.3.0 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.3.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.2 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
github.com/xo/dburl v0.16.0 // indirect
|
github.com/xo/dburl v0.23.1 // indirect
|
||||||
github.com/yuin/goldmark v1.6.0 // indirect
|
github.com/yuin/goldmark v1.6.0 // indirect
|
||||||
github.com/yuin/goldmark-meta v1.1.0 // indirect
|
github.com/yuin/goldmark-meta v1.1.0 // indirect
|
||||||
github.com/zalando/go-keyring v0.2.3 // indirect
|
github.com/zalando/go-keyring v0.2.3 // indirect
|
||||||
github.com/zclconf/go-cty v1.14.1 // indirect
|
github.com/zclconf/go-cty v1.14.2 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
|
||||||
golang.org/x/mod v0.14.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/net v0.18.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/oauth2 v0.13.0 // indirect
|
golang.org/x/oauth2 v0.17.0 // indirect
|
||||||
golang.org/x/sync v0.4.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/term v0.16.0 // indirect
|
golang.org/x/term v0.22.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.14.0 // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
google.golang.org/appengine v1.6.8 // indirect
|
google.golang.org/appengine v1.6.8 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
|
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect
|
||||||
google.golang.org/grpc v1.60.0 // indirect
|
google.golang.org/grpc v1.61.1 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gorm.io/driver/postgres v1.5.4 // indirect
|
gorm.io/driver/postgres v1.5.9 // indirect
|
||||||
gorm.io/driver/sqlite v1.5.4 // indirect
|
gorm.io/driver/sqlite v1.5.6 // indirect
|
||||||
gorm.io/gorm v1.25.5 // indirect
|
gorm.io/gorm v1.25.11 // indirect
|
||||||
modernc.org/libc v1.22.5 // indirect
|
modernc.org/libc v1.41.0 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
modernc.org/memory v1.5.0 // indirect
|
modernc.org/memory v1.7.2 // indirect
|
||||||
modernc.org/sqlite v1.23.1 // indirect
|
modernc.org/sqlite v1.28.0 // indirect
|
||||||
)
|
)
|
||||||
@@ -56,4 +56,8 @@ const (
|
|||||||
ParentScopeIdKey = "parent_scope_id"
|
ParentScopeIdKey = "parent_scope_id"
|
||||||
// GroupMemberIdsKey is used for common "member_ids" resource attribute
|
// GroupMemberIdsKey is used for common "member_ids" resource attribute
|
||||||
GroupMemberIdsKey = "member_ids"
|
GroupMemberIdsKey = "member_ids"
|
||||||
|
// ValueKey is used for common "value" resource attribute
|
||||||
|
ValueKey = "value"
|
||||||
|
// DestinationIdKey is used for common "destination_id" resource attribute
|
||||||
|
DestinationIdKey = "destination_id"
|
||||||
)
|
)
|
||||||
@@ -42,7 +42,7 @@ resource "boundary_scope" "project" {
|
|||||||
|
|
||||||
resource "boundary_role" "org_admin" {
|
resource "boundary_role" "org_admin" {
|
||||||
scope_id = "global"
|
scope_id = "global"
|
||||||
grant_scope_id = boundary_scope.org.id
|
grant_scope_ids = [boundary_scope.org.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func TestAccUserDataSource_globalAdminUser(t *testing.T) {
|
|||||||
resource.TestCheckResourceAttr(dataSourceName, LoginNameKey, "testuser"),
|
resource.TestCheckResourceAttr(dataSourceName, LoginNameKey, "testuser"),
|
||||||
resource.TestMatchResourceAttr(dataSourceName, IDKey, regexache.MustCompile(`^u_.+`)),
|
resource.TestMatchResourceAttr(dataSourceName, IDKey, regexache.MustCompile(`^u_.+`)),
|
||||||
resource.TestMatchResourceAttr(dataSourceName, PrimaryAccountIdKey, regexache.MustCompile(`^acctpw_.+`)),
|
resource.TestMatchResourceAttr(dataSourceName, PrimaryAccountIdKey, regexache.MustCompile(`^acctpw_.+`)),
|
||||||
resource.TestCheckResourceAttr(dataSourceName, "authorized_actions.#", "7"),
|
resource.TestCheckResourceAttr(dataSourceName, "authorized_actions.#", "8"),
|
||||||
resource.TestCheckResourceAttr(dataSourceName, "scope.0.name", "global"),
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.name", "global"),
|
||||||
resource.TestCheckResourceAttr(dataSourceName, "scope.0.id", "global"),
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.id", "global"),
|
||||||
resource.TestCheckResourceAttr(dataSourceName, "scope.0.type", "global"),
|
resource.TestCheckResourceAttr(dataSourceName, "scope.0.type", "global"),
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ func New() *schema.Provider {
|
|||||||
"boundary_account_password": resourceAccountPassword(),
|
"boundary_account_password": resourceAccountPassword(),
|
||||||
"boundary_account_oidc": resourceAccountOidc(),
|
"boundary_account_oidc": resourceAccountOidc(),
|
||||||
"boundary_account_ldap": resourceAccountLdap(),
|
"boundary_account_ldap": resourceAccountLdap(),
|
||||||
|
"boundary_alias_target": resourceAliasTarget(),
|
||||||
"boundary_auth_method": resourceAuthMethod(),
|
"boundary_auth_method": resourceAuthMethod(),
|
||||||
"boundary_auth_method_password": resourceAuthMethodPassword(),
|
"boundary_auth_method_password": resourceAuthMethodPassword(),
|
||||||
"boundary_auth_method_oidc": resourceAuthMethodOidc(),
|
"boundary_auth_method_oidc": resourceAuthMethodOidc(),
|
||||||
@@ -120,6 +121,8 @@ func New() *schema.Provider {
|
|||||||
"boundary_host_set": resourceHostSet(),
|
"boundary_host_set": resourceHostSet(),
|
||||||
"boundary_host_set_static": resourceHostSetStatic(),
|
"boundary_host_set_static": resourceHostSetStatic(),
|
||||||
"boundary_host_set_plugin": resourceHostSetPlugin(),
|
"boundary_host_set_plugin": resourceHostSetPlugin(),
|
||||||
|
"boundary_policy_storage": resourcePolicyStorage(),
|
||||||
|
"boundary_scope_policy_attachment": resourceScopePolicyAttachment(),
|
||||||
"boundary_role": resourceRole(),
|
"boundary_role": resourceRole(),
|
||||||
"boundary_scope": resourceScope(),
|
"boundary_scope": resourceScope(),
|
||||||
"boundary_storage_bucket": resourceStorageBucket(),
|
"boundary_storage_bucket": resourceStorageBucket(),
|
||||||
|
|||||||
@@ -106,6 +106,19 @@ provider "boundary" {
|
|||||||
|
|
||||||
func testConfigWithDefaultAuthMethod(url string, res ...string) string {
|
func testConfigWithDefaultAuthMethod(url string, res ...string) string {
|
||||||
provider := fmt.Sprintf(`
|
provider := fmt.Sprintf(`
|
||||||
|
provider "boundary" {
|
||||||
|
addr = "%s"
|
||||||
|
auth_method_login_name = "%s"
|
||||||
|
auth_method_password = "%s"
|
||||||
|
}`, url, tcLoginName, tcPassword)
|
||||||
|
|
||||||
|
c := []string{provider}
|
||||||
|
c = append(c, res...)
|
||||||
|
return strings.Join(c, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testConfigWithDeprecatedAuthMethod(url string, res ...string) string {
|
||||||
|
provider := fmt.Sprintf(`
|
||||||
provider "boundary" {
|
provider "boundary" {
|
||||||
addr = "%s"
|
addr = "%s"
|
||||||
password_auth_method_login_name = "%s"
|
password_auth_method_login_name = "%s"
|
||||||
@@ -256,6 +269,28 @@ func TestConfigWithDefaultAuthMethod(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigWithDeprecatedAuthMethod(t *testing.T) {
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
defer tc.Shutdown()
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
IsUnitTest: true,
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
CheckDestroy: testAccCheckScopeResourceDestroy(t, provider),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testConfigWithDeprecatedAuthMethod(url, fooOrg, firstProjectFoo, secondProject),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
|
||||||
|
testProviderTokenExists(provider),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigWithoutAMPWCredentials(t *testing.T) {
|
func TestConfigWithoutAMPWCredentials(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
defer tc.Shutdown()
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ resource "boundary_user" "alice" {
|
|||||||
|
|
||||||
resource "boundary_role" "ldap_principal" {
|
resource "boundary_role" "ldap_principal" {
|
||||||
scope_id = boundary_scope.global.id
|
scope_id = boundary_scope.global.id
|
||||||
grant_scope_id = boundary_scope.global.id
|
grant_scope_ids = [boundary_scope.global.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = [boundary_user.alice.id]
|
principal_ids = [boundary_user.alice.id]
|
||||||
}`
|
}`
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api"
|
||||||
|
"github.com/hashicorp/boundary/api/aliases"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
aliasTypeTarget = "target"
|
||||||
|
|
||||||
|
aliasTargetAuthorizeSessionHostIdKey = "authorize_session_host_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAliasTarget() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Description: "The target alias resource allows you to configure a Boundary target alias.",
|
||||||
|
|
||||||
|
CreateContext: resourceTargetAliasCreate,
|
||||||
|
ReadContext: resourceTargetAliasRead,
|
||||||
|
UpdateContext: resourceTargetAliasUpdate,
|
||||||
|
DeleteContext: resourceTargetAliasDelete,
|
||||||
|
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 alias name. Defaults to the resource name.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
DescriptionKey: {
|
||||||
|
Description: "The alias description.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
ScopeIdKey: {
|
||||||
|
Description: "The scope ID.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
ValueKey: {
|
||||||
|
Description: "The value of the alias.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
DestinationIdKey: {
|
||||||
|
Description: "The destination of the alias.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Target specific configurable parameters
|
||||||
|
aliasTargetAuthorizeSessionHostIdKey: {
|
||||||
|
Description: "The host id to pass to Boundary when performing an authorize session action.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
TypeKey: {
|
||||||
|
Description: "The type of alias; hardcoded.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Default: aliasTypeTarget,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFromTargetAliasResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
|
||||||
|
if err := d.Set(NameKey, raw["name"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(DescriptionKey, raw["description"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(ScopeIdKey, raw["scope_id"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(ValueKey, raw["value"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(DestinationIdKey, raw["destination_id"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(TypeKey, raw["type"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attrsVal, ok := raw["attributes"]; ok {
|
||||||
|
attrs := attrsVal.(map[string]interface{})
|
||||||
|
tarAttrs, err := aliases.AttributesMapToTargetAliasAttributes(attrs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if tarAttrs.AuthorizeSessionArguments != nil && tarAttrs.AuthorizeSessionArguments.HostId != "" {
|
||||||
|
if err := d.Set(aliasTargetAuthorizeSessionHostIdKey, tarAttrs.AuthorizeSessionArguments.HostId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(raw["id"].(string))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceTargetAliasCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
|
||||||
|
var scopeId string
|
||||||
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||||
|
scopeId = scopeIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no scope ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeStr string
|
||||||
|
if typeVal, ok := d.GetOk(TypeKey); ok {
|
||||||
|
typeStr = typeVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no type provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := []aliases.Option{}
|
||||||
|
|
||||||
|
if typeVal, ok := d.GetOk(ValueKey); ok {
|
||||||
|
opts = append(opts, aliases.WithValue(typeVal.(string)))
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no alias value provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
|
opts = append(opts, aliases.WithName(nameVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
|
opts = append(opts, aliases.WithDescription(descVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if destVal, ok := d.GetOk(DestinationIdKey); ok {
|
||||||
|
opts = append(opts, aliases.WithDestinationId(destVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if hostIdVal, ok := d.GetOk(aliasTargetAuthorizeSessionHostIdKey); ok {
|
||||||
|
opts = append(opts, aliases.WithTargetAliasAuthorizeSessionArgumentsHostId(hostIdVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasClient := aliases.NewClient(md.client)
|
||||||
|
|
||||||
|
alcr, err := aliasClient.Create(ctx, typeStr, scopeId, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error creating alias: %v", err)
|
||||||
|
}
|
||||||
|
if alcr == nil {
|
||||||
|
return diag.Errorf("nil alias after create")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromTargetAliasResponseMap(d, alcr.GetResponse().Map); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceTargetAliasRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
alClient := aliases.NewClient(md.client)
|
||||||
|
|
||||||
|
alrr, err := alClient.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 alrr == nil {
|
||||||
|
return diag.Errorf("auth method nil after read")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromTargetAliasResponseMap(d, alrr.GetResponse().Map); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceTargetAliasUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
alClient := aliases.NewClient(md.client)
|
||||||
|
|
||||||
|
opts := []aliases.Option{}
|
||||||
|
|
||||||
|
if d.HasChange(NameKey) {
|
||||||
|
opts = append(opts, aliases.DefaultName())
|
||||||
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
|
opts = append(opts, aliases.WithName(nameVal.(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange(DescriptionKey) {
|
||||||
|
opts = append(opts, aliases.DefaultDescription())
|
||||||
|
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
|
opts = append(opts, aliases.WithDescription(descVal.(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange(ValueKey) {
|
||||||
|
if valVal, ok := d.GetOk(ValueKey); ok {
|
||||||
|
opts = append(opts, aliases.WithValue(valVal.(string)))
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no value provided")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange(DestinationIdKey) {
|
||||||
|
opts = append(opts, aliases.DefaultDestinationId())
|
||||||
|
if destId, ok := d.GetOk(DestinationIdKey); ok {
|
||||||
|
opts = append(opts, aliases.WithDestinationId(destId.(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange(aliasTargetAuthorizeSessionHostIdKey) {
|
||||||
|
opts = append(opts, aliases.DefaultTargetAliasAuthorizeSessionArgumentsHostId())
|
||||||
|
if authSessHostId, ok := d.GetOk(aliasTargetAuthorizeSessionHostIdKey); ok {
|
||||||
|
opts = append(opts, aliases.WithTargetAliasAuthorizeSessionArgumentsHostId(authSessHostId.(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opts = append(opts, aliases.WithAutomaticVersioning(true))
|
||||||
|
alur, err := alClient.Update(ctx, d.Id(), 0, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error updating auth method: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromTargetAliasResponseMap(d, alur.GetResponse().Map); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceTargetAliasDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
client := aliases.NewClient(md.client)
|
||||||
|
|
||||||
|
_, err := client.Delete(ctx, d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error deleting alias: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api"
|
||||||
|
"github.com/hashicorp/boundary/api/aliases"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type aliasDestroyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
targetAliasType aliasDestroyType = "boundary_alias_target"
|
||||||
|
|
||||||
|
targetAliasResc = "boundary_alias_target.example"
|
||||||
|
targetAliasName = "foo"
|
||||||
|
targetAliasDesc = "the foo"
|
||||||
|
targetAliasValue = "value.example"
|
||||||
|
targetAliasValueUpdated = "value.example.updated"
|
||||||
|
targetAliasNamespace = "target"
|
||||||
|
targetAliasUpdate = "_random"
|
||||||
|
)
|
||||||
|
|
||||||
|
var fooBarTarget = `
|
||||||
|
resource "boundary_target" "foo" {
|
||||||
|
type = "tcp"
|
||||||
|
name = "test"
|
||||||
|
description = "test target"
|
||||||
|
default_port = 22
|
||||||
|
address = "127.0.0.1"
|
||||||
|
scope_id = boundary_scope.proj1.id
|
||||||
|
depends_on = [boundary_role.proj1_admin]
|
||||||
|
}`
|
||||||
|
|
||||||
|
var aliasId string
|
||||||
|
|
||||||
|
func targetAliasResource(name string, description string, value string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "boundary_alias_target" "example" {
|
||||||
|
name = "%s"
|
||||||
|
description = "%s"
|
||||||
|
value = "%s"
|
||||||
|
scope_id = "global"
|
||||||
|
destination_id = boundary_target.foo.id
|
||||||
|
authorize_session_host_id = "hst_1234567890"
|
||||||
|
depends_on = [boundary_target.foo]
|
||||||
|
}`, name, description, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccAliasTarget(t *testing.T) {
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
defer tc.Shutdown()
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
res := targetAliasResource(targetAliasName, targetAliasDesc, targetAliasValue)
|
||||||
|
|
||||||
|
resUpdate := targetAliasResource(targetAliasName+targetAliasUpdate,
|
||||||
|
targetAliasDesc+targetAliasUpdate, targetAliasValueUpdated)
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
CheckDestroy: testAccCheckAliasResourceDestroy(t, provider, targetAliasType),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
// create
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooBarTarget, res),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, NameKey, targetAliasName),
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, DescriptionKey, targetAliasDesc),
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, ValueKey, targetAliasValue),
|
||||||
|
|
||||||
|
testAccCheckAliasResourceExists(provider, targetAliasResc),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
importStep(targetAliasResc),
|
||||||
|
{
|
||||||
|
// update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooBarTarget, resUpdate),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, NameKey, targetAliasName+targetAliasUpdate),
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, DescriptionKey, targetAliasDesc+targetAliasUpdate),
|
||||||
|
resource.TestCheckResourceAttr(targetAliasResc, ValueKey, targetAliasValueUpdated),
|
||||||
|
|
||||||
|
testAccCheckAliasResourceExists(provider, targetAliasResc),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
importStep(targetAliasResc),
|
||||||
|
{
|
||||||
|
// Run a plan only update and verify no changes
|
||||||
|
PlanOnly: true,
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooBarTarget, resUpdate),
|
||||||
|
},
|
||||||
|
importStep(targetAliasResc),
|
||||||
|
{
|
||||||
|
// update again but apply a preConfig to externally update resource
|
||||||
|
// TODO: Boundary currently causes an error on moving back to a previously
|
||||||
|
// used token, for now verify that a plan only step had changes
|
||||||
|
PreConfig: func() { targetAliasExternalUpdate(t, provider) },
|
||||||
|
PlanOnly: true,
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooBarTarget, resUpdate),
|
||||||
|
},
|
||||||
|
importStep(targetAliasResc),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetAliasExternalUpdate(t *testing.T, testProvider *schema.Provider) {
|
||||||
|
if aliasId == "" {
|
||||||
|
t.Fatal("aliasId must be set before testing an external update")
|
||||||
|
}
|
||||||
|
|
||||||
|
md := testProvider.Meta().(*metaData)
|
||||||
|
ac := aliases.NewClient(md.client)
|
||||||
|
ar, err := ac.Read(context.Background(), aliasId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(fmt.Errorf("got an error reading %q: %w", storeId, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// update alias options
|
||||||
|
var opts []aliases.Option
|
||||||
|
opts = append(opts, aliases.WithDescription("this is an updated description, my guy"))
|
||||||
|
|
||||||
|
_, err = ac.Update(context.Background(), ar.Item.Id, ar.Item.Version, opts...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(fmt.Errorf("got an error updating %q: %w", ar.Item.Id, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAliasResourceExists(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")
|
||||||
|
}
|
||||||
|
aliasId = id
|
||||||
|
|
||||||
|
md := testProvider.Meta().(*metaData)
|
||||||
|
c := aliases.NewClient(md.client)
|
||||||
|
if _, err := c.Read(context.Background(), id); err != nil {
|
||||||
|
return fmt.Errorf("got an error reading %q: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAliasResourceDestroy(t *testing.T, testProvider *schema.Provider, typ aliasDestroyType) 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 string(typ):
|
||||||
|
id := rs.Primary.ID
|
||||||
|
|
||||||
|
c := aliases.NewClient(md.client)
|
||||||
|
_, err := c.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 target alias %q: %v", id, err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,11 @@ func resourceHostCatalogPlugin() *schema.Resource {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
WorkerFilterKey: {
|
||||||
|
Description: "HCP Only. A filter used to control which PKI workers can handle dynamic host catalog requests.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
internalSecretsConfigHmacKey: {
|
internalSecretsConfigHmacKey: {
|
||||||
Description: "Internal only. HMAC of (serverSecretsHmac + config secrets). Used for proper secrets handling.",
|
Description: "Internal only. HMAC of (serverSecretsHmac + config secrets). Used for proper secrets handling.",
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
@@ -294,6 +299,9 @@ func setFromHostCatalogPluginResponseMap(d *schema.ResourceData, raw map[string]
|
|||||||
if err := d.Set(ScopeIdKey, raw[ScopeIdKey]); err != nil {
|
if err := d.Set(ScopeIdKey, raw[ScopeIdKey]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := d.Set(WorkerFilterKey, raw[WorkerFilterKey]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Plugin stuff
|
// Plugin stuff
|
||||||
{
|
{
|
||||||
if err := d.Set(PluginIdKey, raw[PluginIdKey]); err != nil {
|
if err := d.Set(PluginIdKey, raw[PluginIdKey]); err != nil {
|
||||||
@@ -399,6 +407,12 @@ func resourceHostCatalogPluginCreate(ctx context.Context, d *schema.ResourceData
|
|||||||
opts = append(opts, hostcatalogs.WithDescription(descStr))
|
opts = append(opts, hostcatalogs.WithDescription(descStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workerFilterVal, ok := d.GetOk(WorkerFilterKey)
|
||||||
|
if ok {
|
||||||
|
workerFilterStr := workerFilterVal.(string)
|
||||||
|
opts = append(opts, hostcatalogs.WithWorkerFilter(workerFilterStr))
|
||||||
|
}
|
||||||
|
|
||||||
attrsVal, ok := d.GetOk(AttributesJsonKey)
|
attrsVal, ok := d.GetOk(AttributesJsonKey)
|
||||||
if ok {
|
if ok {
|
||||||
attrsStr, err := parseutil.ParsePath(attrsVal.(string))
|
attrsStr, err := parseutil.ParsePath(attrsVal.(string))
|
||||||
@@ -556,6 +570,15 @@ func resourceHostCatalogPluginUpdate(ctx context.Context, d *schema.ResourceData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.HasChange(WorkerFilterKey) {
|
||||||
|
opts = append(opts, hostcatalogs.DefaultWorkerFilter())
|
||||||
|
workerFilterVal, ok := d.GetOk(WorkerFilterKey)
|
||||||
|
if ok {
|
||||||
|
workerFilterStr := workerFilterVal.(string)
|
||||||
|
opts = append(opts, hostcatalogs.WithWorkerFilter(workerFilterStr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if d.HasChange(AttributesJsonKey) {
|
if d.HasChange(AttributesJsonKey) {
|
||||||
attrsVal, ok := d.GetOk(AttributesJsonKey)
|
attrsVal, ok := d.GetOk(AttributesJsonKey)
|
||||||
if ok {
|
if ok {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ const (
|
|||||||
testPluginHostCatalogDescription = "bar"
|
testPluginHostCatalogDescription = "bar"
|
||||||
testPluginHostCatalogDescriptionUpdate = "bar foo"
|
testPluginHostCatalogDescriptionUpdate = "bar foo"
|
||||||
testPluginHostCatalogDescriptionUpdate2 = "bar foo foo"
|
testPluginHostCatalogDescriptionUpdate2 = "bar foo foo"
|
||||||
|
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate = "\"dev\" in \"/tags/type\""
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate2 = "\"pki\" in \"/tags/type\""
|
||||||
)
|
)
|
||||||
|
|
||||||
// expectedAttributesState is used here and in plugin host sets to control how
|
// expectedAttributesState is used here and in plugin host sets to control how
|
||||||
@@ -244,6 +247,212 @@ func TestAccPluginHostCatalog(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccPluginHostCatalogWithWorkerFilter(t *testing.T) {
|
||||||
|
t.Skip("Skipping test until Boundary Terraform Provider can unit tests for Boundary Enterprise only features")
|
||||||
|
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
defer tc.Shutdown()
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
resName := "boundary_host_catalog_plugin.foo"
|
||||||
|
initialValuesStr := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
attributes_json = jsonencode({
|
||||||
|
foo = "bar"
|
||||||
|
zip = "zap"
|
||||||
|
})
|
||||||
|
secrets_json = jsonencode({
|
||||||
|
hush = "puppies"
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescription,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Changed description, secrets and added worker filter.
|
||||||
|
valuesStrUpdate1 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
worker_filter = %q
|
||||||
|
attributes_json = jsonencode({
|
||||||
|
foo = "bar"
|
||||||
|
zip = "zoop"
|
||||||
|
})
|
||||||
|
secrets_json = jsonencode({
|
||||||
|
flush = "fluppies"
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate,
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Changed description, no secrets update, nullify worker filter.
|
||||||
|
valuesStrUpdate2 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
worker_filter = null
|
||||||
|
attributes_json = jsonencode({
|
||||||
|
foo = "bar"
|
||||||
|
zip = "zoop"
|
||||||
|
})
|
||||||
|
secrets_json = jsonencode({
|
||||||
|
flush = "fluppies"
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate2,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Same description and set a worker filter again, now empty secrets.
|
||||||
|
valuesStrUpdate3 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
worker_filter = %q
|
||||||
|
attributes_json = jsonencode({
|
||||||
|
foo = "bar"
|
||||||
|
zip = "zoop"
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate2,
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate2,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Same description, now explicitly unset secrets and blankify attrs and
|
||||||
|
// worker filter.
|
||||||
|
valuesStrUpdate4 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
secrets_json = "null"
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate2,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set values again
|
||||||
|
valuesStrUpdate5 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
worker_filter = %q
|
||||||
|
attributes_json = jsonencode({
|
||||||
|
foo = "bar"
|
||||||
|
zip = "zoop"
|
||||||
|
})
|
||||||
|
secrets_json = jsonencode({
|
||||||
|
flush = "fluppies"
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate2,
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate2,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Explicitly set both secrets and attributes to null
|
||||||
|
valuesStrUpdate6 := fmt.Sprintf(`
|
||||||
|
description = "%s"
|
||||||
|
worker_filter = %q
|
||||||
|
attributes_json = "null"
|
||||||
|
secrets_json = "null"
|
||||||
|
`,
|
||||||
|
testPluginHostCatalogDescriptionUpdate2,
|
||||||
|
testPluginHostCatalogWorkerFilterUpdate2,
|
||||||
|
)
|
||||||
|
|
||||||
|
initialHcl := fmt.Sprintf(projPluginHostCatalogBase, initialValuesStr)
|
||||||
|
update1Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate1)
|
||||||
|
update2Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate2)
|
||||||
|
update3Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate3)
|
||||||
|
update4Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate4)
|
||||||
|
update5Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate5)
|
||||||
|
update6Hcl := fmt.Sprintf(projPluginHostCatalogBase, valuesStrUpdate6)
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
CheckDestroy: testAccCheckHostCatalogResourceDestroy(t, provider, baseHostCatalogType),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
// test create
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, initialHcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
|
||||||
|
testAccCheckScopeResourceExists(provider, "boundary_scope.proj1"),
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslyEmptyNowSet),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescription),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update1Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetButChanged),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate),
|
||||||
|
resource.TestCheckResourceAttr(resName, WorkerFilterKey, testPluginHostCatalogWorkerFilterUpdate),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update2Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetNoChange),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// this runs the same HCL; mostly used in some manual checking
|
||||||
|
// to ensure update is still called even when nothing has
|
||||||
|
// changed (as we need for secrets)
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update2Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetNoChange),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update3Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetNoChange),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
resource.TestCheckResourceAttr(resName, WorkerFilterKey, testPluginHostCatalogWorkerFilterUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update4Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetNowEmpty),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update5Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslyEmptyNowSet),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
resource.TestCheckResourceAttr(resName, WorkerFilterKey, testPluginHostCatalogWorkerFilterUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
{
|
||||||
|
// test update
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, update6Hcl),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckPluginHostCatalogResourceExists(provider, resName, expectedAttributesStatePreviouslySetNowEmpty),
|
||||||
|
resource.TestCheckResourceAttr(resName, DescriptionKey, testPluginHostCatalogDescriptionUpdate2),
|
||||||
|
resource.TestCheckResourceAttr(resName, WorkerFilterKey, testPluginHostCatalogWorkerFilterUpdate2),
|
||||||
|
),
|
||||||
|
ExpectNonEmptyPlan: true,
|
||||||
|
},
|
||||||
|
importStep(resName, SecretsJsonKey, internalHmacUsedForSecretsConfigHmacKey, internalForceUpdateKey, internalSecretsConfigHmacKey),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckPluginHostCatalogResourceExists(testProvider *schema.Provider, name string, expAttrState expectedAttributesState) resource.TestCheckFunc {
|
func testAccCheckPluginHostCatalogResourceExists(testProvider *schema.Provider, name string, expAttrState expectedAttributesState) 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]
|
||||||
|
|||||||
@@ -0,0 +1,303 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api"
|
||||||
|
"github.com/hashicorp/boundary/api/policies"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
policyStorageRetainForDaysKey = "retain_for_days"
|
||||||
|
policyStorageRetainForOverridableKey = "retain_for_overridable"
|
||||||
|
policyStorageDeleteAfterDaysKey = "delete_after_days"
|
||||||
|
policyStorageDeleteAfterOverridableKey = "delete_after_overridable"
|
||||||
|
policyTypeStorage = "storage"
|
||||||
|
daysField = "days"
|
||||||
|
overridableField = "overridable"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourcePolicyStorage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Description: "The storage policy resource allows you to configure a Boundary storage policy. " +
|
||||||
|
"Storage policies allow an admin to configure how long session recordings must be stored and when " +
|
||||||
|
"to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.",
|
||||||
|
CreateContext: resourcePolicyStorageCreate,
|
||||||
|
ReadContext: resourcePolicyStorageRead,
|
||||||
|
UpdateContext: resourcePolicyStorageUpdate,
|
||||||
|
DeleteContext: resourcePolicyStorageDelete,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
StateContext: schema.ImportStatePassthroughContext,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
IDKey: {
|
||||||
|
Description: "The ID of the policy.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
NameKey: {
|
||||||
|
Description: "The policy name. Defaults to the resource name.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
DescriptionKey: {
|
||||||
|
Description: "The policy description.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
ScopeIdKey: {
|
||||||
|
Description: "The scope for this policy.",
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
policyStorageRetainForDaysKey: {
|
||||||
|
Description: "The number of days a session recording is required to be stored. Defaults to 0: allow deletions at any time. However, " + policyStorageRetainForDaysKey + " and " + policyStorageDeleteAfterDaysKey + " cannot both be 0.",
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
AtLeastOneOf: []string{policyStorageDeleteAfterDaysKey},
|
||||||
|
},
|
||||||
|
policyStorageRetainForOverridableKey: {
|
||||||
|
Description: "Whether or not the associated " + policyStorageRetainForDaysKey + " value can be overridden by org scopes. Note: if the associated " + policyStorageRetainForDaysKey + " value is 0, overridable is ignored.",
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
policyStorageDeleteAfterDaysKey: {
|
||||||
|
Description: "The number of days after which a session recording will be automatically deleted. Defaults to 0: never automatically delete. However, " + policyStorageDeleteAfterDaysKey + " and " + policyStorageRetainForDaysKey + " cannot both be 0.",
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
AtLeastOneOf: []string{policyStorageRetainForDaysKey},
|
||||||
|
},
|
||||||
|
policyStorageDeleteAfterOverridableKey: {
|
||||||
|
Description: "Whether or not the associated " + policyStorageDeleteAfterDaysKey + " value can be overridden by org scopes. Note: if the associated " + policyStorageDeleteAfterDaysKey + " value is 0, overridable is ignored",
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFromPolicyItem(d *schema.ResourceData, p *policies.Policy) error {
|
||||||
|
d.SetId(p.Id)
|
||||||
|
|
||||||
|
if err := d.Set(NameKey, p.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set(DescriptionKey, p.Description); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set(ScopeIdKey, p.ScopeId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse attributes to the retain/delete values so that the tf syntax is simpler
|
||||||
|
attributes, err := p.GetStoragePolicyAttributes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain_for attribute
|
||||||
|
if attributes.RetainFor != nil {
|
||||||
|
if err := d.Set(policyStorageRetainForDaysKey, attributes.RetainFor.Days); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(policyStorageRetainForOverridableKey, attributes.RetainFor.Overridable); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no RetainFor, set to nil
|
||||||
|
if err := d.Set(policyStorageRetainForDaysKey, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(policyStorageRetainForOverridableKey, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete_after attribute
|
||||||
|
if attributes.DeleteAfter != nil {
|
||||||
|
if err := d.Set(policyStorageDeleteAfterDaysKey, attributes.DeleteAfter.Days); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(policyStorageDeleteAfterOverridableKey, attributes.DeleteAfter.Overridable); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no DeleteAfter, set to nil
|
||||||
|
if err := d.Set(policyStorageDeleteAfterDaysKey, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.Set(policyStorageDeleteAfterOverridableKey, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePolicyStorageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
pClient := policies.NewClient(md.client)
|
||||||
|
opts := []policies.Option{}
|
||||||
|
|
||||||
|
var scopeId string
|
||||||
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||||
|
scopeId = scopeIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no scope ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
|
opts = append(opts, policies.WithName(nameVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if descVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
|
opts = append(opts, policies.WithDescription(descVal.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if retainDaysVal, ok := d.GetOk(policyStorageRetainForDaysKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyRetainForDays(int32(retainDaysVal.(int))))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyRetainForDays())
|
||||||
|
}
|
||||||
|
if retainOverrideVal, ok := d.GetOk(policyStorageRetainForOverridableKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyRetainForOverridable(retainOverrideVal.(bool)))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyRetainForOverridable())
|
||||||
|
}
|
||||||
|
|
||||||
|
if deleteDaysVal, ok := d.GetOk(policyStorageDeleteAfterDaysKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyDeleteAfterDays(int32(deleteDaysVal.(int))))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterDays())
|
||||||
|
}
|
||||||
|
if deleteOverrideVal, ok := d.GetOk(policyStorageDeleteAfterOverridableKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyDeleteAfterOverridable(deleteOverrideVal.(bool)))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterOverridable())
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := pClient.Create(ctx, policyTypeStorage, scopeId, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error creating storage policy: %v", err)
|
||||||
|
}
|
||||||
|
if p == nil {
|
||||||
|
return diag.Errorf("nil storage policy after create")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePolicyStorageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
pClient := policies.NewClient(md.client)
|
||||||
|
|
||||||
|
p, err := pClient.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 policy: %v", err)
|
||||||
|
}
|
||||||
|
if p == nil {
|
||||||
|
return diag.Errorf("policy nil after read")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePolicyStorageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
pClient := policies.NewClient(md.client)
|
||||||
|
opts := []policies.Option{}
|
||||||
|
|
||||||
|
if d.HasChange(NameKey) {
|
||||||
|
if nameVal, ok := d.GetOk(NameKey); ok {
|
||||||
|
name := nameVal.(string)
|
||||||
|
opts = append(opts, policies.WithName(name))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange(DescriptionKey) {
|
||||||
|
if descriptionVal, ok := d.GetOk(DescriptionKey); ok {
|
||||||
|
description := descriptionVal.(string)
|
||||||
|
opts = append(opts, policies.WithDescription(description))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultDescription())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChanges(policyStorageRetainForDaysKey, policyStorageRetainForOverridableKey) {
|
||||||
|
if retainDaysVal, ok := d.GetOk(policyStorageRetainForDaysKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyRetainForDays(int32(retainDaysVal.(int))))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyRetainForDays())
|
||||||
|
}
|
||||||
|
if retainOverrideVal, ok := d.GetOk(policyStorageRetainForOverridableKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyRetainForOverridable(retainOverrideVal.(bool)))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyRetainForOverridable())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChanges(policyStorageDeleteAfterDaysKey, policyStorageDeleteAfterOverridableKey) {
|
||||||
|
if deleteDaysVal, ok := d.GetOk(policyStorageDeleteAfterDaysKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyDeleteAfterDays(int32(deleteDaysVal.(int))))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterDays())
|
||||||
|
}
|
||||||
|
if deleteOverrideVal, ok := d.GetOk(policyStorageDeleteAfterOverridableKey); ok {
|
||||||
|
opts = append(opts, policies.WithStoragePolicyDeleteAfterOverridable(deleteOverrideVal.(bool)))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterOverridable())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opts = append(opts, policies.WithAutomaticVersioning(true))
|
||||||
|
p, err := pClient.Update(ctx, d.Id(), 0, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error creating storage policy: %v", err)
|
||||||
|
}
|
||||||
|
if p == nil {
|
||||||
|
return diag.Errorf("nil storage policy after create")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePolicyStorageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
pClient := policies.NewClient(md.client)
|
||||||
|
|
||||||
|
_, err := pClient.Delete(ctx, d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return diag.Errorf("error deleting policy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -5,7 +5,12 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"github.com/hashicorp/boundary/api"
|
"github.com/hashicorp/boundary/api"
|
||||||
"github.com/hashicorp/boundary/api/roles"
|
"github.com/hashicorp/boundary/api/roles"
|
||||||
@@ -14,9 +19,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
roleGrantScopeIdKey = "grant_scope_id"
|
roleGrantScopeIdsKey = "grant_scope_ids"
|
||||||
rolePrincipalIdsKey = "principal_ids"
|
rolePrincipalIdsKey = "principal_ids"
|
||||||
roleGrantStringsKey = "grant_strings"
|
roleGrantStringsKey = "grant_strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceRole() *schema.Resource {
|
func resourceRole() *schema.Resource {
|
||||||
@@ -60,15 +65,17 @@ func resourceRole() *schema.Resource {
|
|||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
},
|
},
|
||||||
roleGrantStringsKey: {
|
roleGrantStringsKey: {
|
||||||
Description: " A list of stringified grants for the role.",
|
Description: "A list of stringified grants for the role.",
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
},
|
},
|
||||||
roleGrantScopeIdKey: {
|
roleGrantScopeIdsKey: {
|
||||||
Type: schema.TypeString,
|
Description: `A list of scopes for which the grants in this role should apply, which can include the special values "this", "children", or "descendants"`,
|
||||||
Optional: true,
|
Type: schema.TypeSet,
|
||||||
Computed: true,
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Computed: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -90,14 +97,15 @@ func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{})
|
|||||||
if err := d.Set(roleGrantStringsKey, raw["grant_strings"]); err != nil {
|
if err := d.Set(roleGrantStringsKey, raw["grant_strings"]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := d.Set(roleGrantScopeIdKey, raw["grant_scope_id"]); err != nil {
|
if err := d.Set(roleGrantScopeIdsKey, raw["grant_scope_ids"]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.SetId(raw["id"].(string))
|
d.SetId(raw["id"].(string))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
|
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (diags diag.Diagnostics) {
|
||||||
md := meta.(*metaData)
|
md := meta.(*metaData)
|
||||||
|
|
||||||
var scopeId string
|
var scopeId string
|
||||||
@@ -121,10 +129,13 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
opts = append(opts, roles.WithDescription(descStr))
|
opts = append(opts, roles.WithDescription(descStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
grantScopeIdVal, ok := d.GetOk(roleGrantScopeIdKey)
|
var grantScopeIds []string
|
||||||
if ok {
|
if grantScopeIdsVal, ok := d.GetOk(roleGrantScopeIdsKey); ok {
|
||||||
grantScopeIdStr := grantScopeIdVal.(string)
|
list := grantScopeIdsVal.(*schema.Set).List()
|
||||||
opts = append(opts, roles.WithGrantScopeId(grantScopeIdStr))
|
grantScopeIds = make([]string, 0, len(list))
|
||||||
|
for _, i := range list {
|
||||||
|
grantScopeIds = append(grantScopeIds, i.(string))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var principalIds []string
|
var principalIds []string
|
||||||
@@ -141,6 +152,16 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
list := grantStringsVal.(*schema.Set).List()
|
list := grantStringsVal.(*schema.Set).List()
|
||||||
grantStrings = make([]string, 0, len(list))
|
grantStrings = make([]string, 0, len(list))
|
||||||
for _, i := range list {
|
for _, i := range list {
|
||||||
|
for _, grant := range list {
|
||||||
|
deprecationNotice, err := checkGrantForDeprecation(grant.(string))
|
||||||
|
if err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
if deprecationNotice != "" {
|
||||||
|
diags = append(diags, diag.Diagnostic{Severity: diag.Warning, Summary: "deprecated field found in grant", Detail: deprecationNotice})
|
||||||
|
}
|
||||||
|
grantStrings = append(grantStrings, grant.(string))
|
||||||
|
}
|
||||||
grantStrings = append(grantStrings, i.(string))
|
grantStrings = append(grantStrings, i.(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +178,7 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
apiResponse := tcr.GetResponse().Map
|
apiResponse := tcr.GetResponse().Map
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := setFromRoleResponseMap(d, apiResponse); err != nil {
|
if err := setFromRoleResponseMap(d, apiResponse); err != nil {
|
||||||
errs = append(errs, diag.FromErr(err)...)
|
diags = append(diags, diag.FromErr(err)...)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -165,9 +186,9 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
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))
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
|
||||||
case tspr == nil:
|
case tspr == nil:
|
||||||
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principals"})
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principals"})
|
||||||
default:
|
default:
|
||||||
apiResponse = tspr.GetResponse().Map
|
apiResponse = tspr.GetResponse().Map
|
||||||
}
|
}
|
||||||
@@ -177,15 +198,27 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true))
|
tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true))
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
|
||||||
case tsgr == nil:
|
case tsgr == nil:
|
||||||
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grants"})
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grants"})
|
||||||
default:
|
default:
|
||||||
apiResponse = tsgr.GetResponse().Map
|
apiResponse = tsgr.GetResponse().Map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
if grantScopeIds != nil {
|
||||||
|
tsgr, err := rc.SetGrantScopes(ctx, tcr.Item.Id, 0, grantScopeIds, roles.WithAutomaticVersioning(true))
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grant scopes", Detail: err.Error()})
|
||||||
|
case tsgr == nil:
|
||||||
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grant scope ids"})
|
||||||
|
default:
|
||||||
|
apiResponse = tsgr.GetResponse().Map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
@@ -239,17 +272,6 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var grantScopeId *string
|
|
||||||
if d.HasChange(roleGrantScopeIdKey) {
|
|
||||||
opts = append(opts, roles.DefaultGrantScopeId())
|
|
||||||
grantScopeIdVal, ok := d.GetOk(roleGrantScopeIdKey)
|
|
||||||
if ok {
|
|
||||||
grantScopeIdStr := grantScopeIdVal.(string)
|
|
||||||
grantScopeId = &grantScopeIdStr
|
|
||||||
opts = append(opts, roles.WithGrantScopeId(grantScopeIdStr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
opts = append(opts, roles.WithAutomaticVersioning(true))
|
opts = append(opts, roles.WithAutomaticVersioning(true))
|
||||||
_, err := rc.Update(ctx, d.Id(), 0, opts...)
|
_, err := rc.Update(ctx, d.Id(), 0, opts...)
|
||||||
@@ -268,11 +290,6 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
return diag.FromErr(err)
|
return diag.FromErr(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d.HasChange(roleGrantScopeIdKey) {
|
|
||||||
if err := d.Set(roleGrantScopeIdKey, grantScopeId); err != nil {
|
|
||||||
return diag.FromErr(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var diags diag.Diagnostics
|
var diags diag.Diagnostics
|
||||||
if d.HasChange(roleGrantStringsKey) {
|
if d.HasChange(roleGrantStringsKey) {
|
||||||
@@ -280,6 +297,13 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
if grantStringsVal, ok := d.GetOk(roleGrantStringsKey); ok {
|
if grantStringsVal, ok := d.GetOk(roleGrantStringsKey); ok {
|
||||||
grants := grantStringsVal.(*schema.Set).List()
|
grants := grantStringsVal.(*schema.Set).List()
|
||||||
for _, grant := range grants {
|
for _, grant := range grants {
|
||||||
|
deprecationNotice, err := checkGrantForDeprecation(grant.(string))
|
||||||
|
if err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
if deprecationNotice != "" {
|
||||||
|
diags = append(diags, diag.Diagnostic{Severity: diag.Warning, Summary: "deprecated field found in grant", Detail: deprecationNotice})
|
||||||
|
}
|
||||||
grantStrings = append(grantStrings, grant.(string))
|
grantStrings = append(grantStrings, grant.(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,6 +335,24 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.HasChange(roleGrantScopeIdsKey) {
|
||||||
|
var grantScopeIds []string
|
||||||
|
if grantScopeIdsVal, ok := d.GetOk(roleGrantScopeIdsKey); ok {
|
||||||
|
grantScopes := grantScopeIdsVal.(*schema.Set).List()
|
||||||
|
for _, grantScope := range grantScopes {
|
||||||
|
grantScopeIds = append(grantScopeIds, grantScope.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := rc.SetGrantScopes(ctx, d.Id(), 0, grantScopeIds, roles.WithAutomaticVersioning(true))
|
||||||
|
if err != nil {
|
||||||
|
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grant scopes", Detail: err.Error()})
|
||||||
|
} else {
|
||||||
|
if err := d.Set(roleGrantScopeIdsKey, grantScopeIds); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,3 +367,35 @@ func resourceRoleDelete(ctx context.Context, d *schema.ResourceData, meta interf
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkGrantForDeprecation(grantString string) (string, error) {
|
||||||
|
if len(grantString) == 0 {
|
||||||
|
return "", errors.New("missing grant string")
|
||||||
|
}
|
||||||
|
grantString = strings.ToValidUTF8(grantString, string(unicode.ReplacementChar))
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case grantString[0] == '{':
|
||||||
|
raw := make(map[string]any, 4)
|
||||||
|
if err := json.Unmarshal([]byte(grantString), &raw); err != nil {
|
||||||
|
return "", fmt.Errorf("error json unmarshalling grant string: %w", err)
|
||||||
|
}
|
||||||
|
if raw["id"] != nil {
|
||||||
|
return `Grant contains an "id" field which is deprecated and will not be accepted from Boundary 0.15+. Please use "ids" instead.`, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
parts := strings.Split(grantString, ";")
|
||||||
|
for _, part := range parts {
|
||||||
|
splitPart := strings.Split(part, "=")
|
||||||
|
if len(splitPart) < 2 {
|
||||||
|
return "", fmt.Errorf("invalid grant part: %s", part)
|
||||||
|
}
|
||||||
|
if splitPart[0] == "id" {
|
||||||
|
return `Grant contains an "id" field which is deprecated and will not be accepted from Boundary 0.15+. Please use "ids" instead.`, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api/roles"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
orgRoleWithGrantScopes = `
|
||||||
|
resource "boundary_role" "with_grant_scopes" {
|
||||||
|
name = "with_grant_scopes"
|
||||||
|
description = "with grant scopes"
|
||||||
|
principal_ids = [boundary_user.foo.id]
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
depends_on = [boundary_role.org1_admin]
|
||||||
|
grant_scope_ids = ["this", "children", boundary_scope.proj1.id]
|
||||||
|
}`
|
||||||
|
|
||||||
|
orgRoleWithGrantScopesUpdate = `
|
||||||
|
resource "boundary_role" "with_grant_scopes" {
|
||||||
|
name = "with_grant_scopes_update"
|
||||||
|
description = "with grant scopes update"
|
||||||
|
principal_ids = [boundary_user.foo.id]
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
depends_on = [boundary_role.org1_admin]
|
||||||
|
grant_scope_ids = ["this"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
orgRoleWithInvalidGrantScopesUpdate = `
|
||||||
|
resource "boundary_role" "with_grant_scopes" {
|
||||||
|
name = "with_grant_scopes_update"
|
||||||
|
description = "with grant scopes update"
|
||||||
|
principal_ids = [boundary_user.foo.id]
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
depends_on = [boundary_role.org1_admin]
|
||||||
|
grant_scope_ids = ["this", "children", "p_foobar1234"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
conversionOrgRoleWithGrantScopeIdsConversion = `
|
||||||
|
resource "boundary_role" "with_grant_scope_id" {
|
||||||
|
name = "grant scope id role"
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
depends_on = [boundary_role.org1_admin]
|
||||||
|
grant_scope_ids = ["this", boundary_scope.proj1.id]
|
||||||
|
}`
|
||||||
|
|
||||||
|
conversionOrgRoleWithGrantScopeIdsUpdate = `
|
||||||
|
resource "boundary_role" "with_grant_scope_id" {
|
||||||
|
name = "grant scope id role"
|
||||||
|
scope_id = boundary_scope.org1.id
|
||||||
|
depends_on = [boundary_role.org1_admin]
|
||||||
|
grant_scope_ids = ["this", "children"]
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestAccRoleWithGrantScopes exercises creation and update with valid and
|
||||||
|
// invalid grant scopes
|
||||||
|
func TestAccRoleWithGrantScopes(t *testing.T) {
|
||||||
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
|
t.Cleanup(tc.Shutdown)
|
||||||
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
|
var provider *schema.Provider
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
IsUnitTest: true,
|
||||||
|
ProviderFactories: providerFactories(&provider),
|
||||||
|
CheckDestroy: testAccCheckRoleResourceDestroy(t, provider),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
// Create with valid grant scopes should create role
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithGrantScopes),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckScopeResourceExists(provider, "boundary_scope.proj1"),
|
||||||
|
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
|
||||||
|
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
|
||||||
|
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scopes", []string{"this", "children", "boundary_scope.proj1"}),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
importStep("boundary_role.with_grant_scopes"),
|
||||||
|
{
|
||||||
|
// Update with invalid grant scopes should update role but return empty plan
|
||||||
|
// since grant scopes were not set correctly.
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithInvalidGrantScopesUpdate),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes update"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes_update"),
|
||||||
|
),
|
||||||
|
ExpectError: regexp.MustCompile(`Unable to set grant scopes on role`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Update again without invalid principal should produce empty plan
|
||||||
|
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithGrantScopesUpdate),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
|
||||||
|
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scopes", []string{"this"}),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes update"),
|
||||||
|
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes_update"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
importStep("boundary_role.with_grant_scopes"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckRoleResourceGrantScopesSet(testProvider *schema.Provider, name string, grantScopeIds []string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("role resource not found: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
id := rs.Primary.ID
|
||||||
|
if id == "" {
|
||||||
|
return fmt.Errorf("role resource ID is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
scopeIds := []string{}
|
||||||
|
for _, grantScope := range grantScopeIds {
|
||||||
|
if grantScope == "children" || grantScope == "this" || grantScope == "descendants" {
|
||||||
|
scopeIds = append(scopeIds, grantScope)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
scope, ok := s.RootModule().Resources[grantScope]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("scope resource not found: %s", grantScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
scopeId := scope.Primary.ID
|
||||||
|
if scopeId == "" {
|
||||||
|
return fmt.Errorf("scope resource ID not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
scopeIds = append(scopeIds, scopeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
md := testProvider.Meta().(*metaData)
|
||||||
|
rolesClient := roles.NewClient(md.client)
|
||||||
|
|
||||||
|
rr, err := rolesClient.Read(context.Background(), id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Got an error when reading role %q: %v", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for every grant scope set on the role in the state, ensure each role
|
||||||
|
// in boundary has the same setings
|
||||||
|
if len(rr.Item.GrantScopeIds) == 0 {
|
||||||
|
return fmt.Errorf("no grant scope ids found in boundary")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stateGrantScopeId := range rr.Item.GrantScopeIds {
|
||||||
|
ok := false
|
||||||
|
for _, gotScopeId := range scopeIds {
|
||||||
|
if gotScopeId == stateGrantScopeId {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("grant scope id in state not set in boundary: %s", stateGrantScopeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -189,7 +189,7 @@ resource "boundary_role" "with_grants" {
|
|||||||
|
|
||||||
func TestAccRoleToOrgToProject(t *testing.T) {
|
func TestAccRoleToOrgToProject(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
t.Cleanup(tc.Shutdown)
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
var provider *schema.Provider
|
var provider *schema.Provider
|
||||||
@@ -243,7 +243,7 @@ func TestAccRoleToOrgToProject(t *testing.T) {
|
|||||||
|
|
||||||
func TestAccRoleWithGrants(t *testing.T) {
|
func TestAccRoleWithGrants(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
t.Cleanup(tc.Shutdown)
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
var provider *schema.Provider
|
var provider *schema.Provider
|
||||||
@@ -302,7 +302,7 @@ func TestAccRoleWithGrants(t *testing.T) {
|
|||||||
|
|
||||||
func TestAccRoleWithPrincipals(t *testing.T) {
|
func TestAccRoleWithPrincipals(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
t.Cleanup(tc.Shutdown)
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
var provider *schema.Provider
|
var provider *schema.Provider
|
||||||
@@ -365,7 +365,7 @@ func TestAccRoleWithPrincipals(t *testing.T) {
|
|||||||
|
|
||||||
func TestAccRoleWithGroups(t *testing.T) {
|
func TestAccRoleWithGroups(t *testing.T) {
|
||||||
tc := controller.NewTestController(t, tcConfig...)
|
tc := controller.NewTestController(t, tcConfig...)
|
||||||
defer tc.Shutdown()
|
t.Cleanup(tc.Shutdown)
|
||||||
url := tc.ApiAddrs()[0]
|
url := tc.ApiAddrs()[0]
|
||||||
|
|
||||||
var provider *schema.Provider
|
var provider *schema.Provider
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/boundary/api"
|
||||||
|
"github.com/hashicorp/boundary/api/scopes"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
policyIdKey = "policy_id"
|
||||||
|
storagePolicyPrefix = "pst_"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceScopePolicyAttachment() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
CreateContext: resourceScopePolicyAttachmentCreate,
|
||||||
|
ReadWithoutTimeout: resourceScopePolicyAttachmentRead,
|
||||||
|
DeleteWithoutTimeout: resourceScopePolicyAttachmentDelete,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
StateContext: schema.ImportStatePassthroughContext,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
ScopeIdKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
policyIdKey: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ForceNew: true,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceScopePolicyAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
scp := scopes.NewClient(md.client)
|
||||||
|
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
|
||||||
|
|
||||||
|
var scopeId string
|
||||||
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||||
|
scopeId = scopeIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no scope ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set(ScopeIdKey, scopeId); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var policyId string
|
||||||
|
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
|
||||||
|
policyId = policyIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no policy ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
// other policy types may be added here and in other switches with this file
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(policyId, storagePolicyPrefix):
|
||||||
|
if _, err := scp.AttachStoragePolicy(ctx, scopeId, 0, policyId, opts...); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return diag.Errorf("unknown policy type provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set(policyIdKey, policyId); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%s:%s", policyId, scopeId))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceScopePolicyAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
scp := scopes.NewClient(md.client)
|
||||||
|
|
||||||
|
var scopeId string
|
||||||
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||||
|
scopeId = scopeIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no scope ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
var policyId string
|
||||||
|
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
|
||||||
|
policyId = policyIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no policy ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := scp.Read(ctx, scopeId)
|
||||||
|
if err != nil {
|
||||||
|
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
||||||
|
// the scope is gone, destroy this resource
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return diag.Errorf("error reading scope: %v", err)
|
||||||
|
}
|
||||||
|
if s == nil {
|
||||||
|
return diag.Errorf("scope nil after read")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(policyId, storagePolicyPrefix):
|
||||||
|
if policyId != s.GetItem().StoragePolicyId {
|
||||||
|
// this policy is no longer attached to the scope, destroy this resource
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return diag.Errorf("unknown policy type provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceScopePolicyAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
md := meta.(*metaData)
|
||||||
|
scp := scopes.NewClient(md.client)
|
||||||
|
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
|
||||||
|
|
||||||
|
var scopeId string
|
||||||
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
||||||
|
scopeId = scopeIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no scope ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
var policyId string
|
||||||
|
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
|
||||||
|
policyId = policyIdVal.(string)
|
||||||
|
} else {
|
||||||
|
return diag.Errorf("no policy ID provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(policyId, storagePolicyPrefix):
|
||||||
|
if _, err := scp.DetachStoragePolicy(ctx, scopeId, 0, opts...); err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return diag.Errorf("unknown policy type provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ resource "boundary_scope" "org1" {
|
|||||||
|
|
||||||
resource "boundary_role" "org1_admin" {
|
resource "boundary_role" "org1_admin" {
|
||||||
scope_id = boundary_scope.global.id
|
scope_id = boundary_scope.global.id
|
||||||
grant_scope_id = boundary_scope.org1.id
|
grant_scope_ids = [boundary_scope.org1.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ resource "boundary_scope" "proj1" {
|
|||||||
|
|
||||||
resource "boundary_role" "proj1_admin" {
|
resource "boundary_role" "proj1_admin" {
|
||||||
scope_id = boundary_scope.org1.id
|
scope_id = boundary_scope.org1.id
|
||||||
grant_scope_id = boundary_scope.proj1.id
|
grant_scope_ids = [boundary_scope.proj1.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ resource "boundary_scope" "proj1" {
|
|||||||
|
|
||||||
resource "boundary_role" "proj1_admin" {
|
resource "boundary_role" "proj1_admin" {
|
||||||
scope_id = boundary_scope.org1.id
|
scope_id = boundary_scope.org1.id
|
||||||
grant_scope_id = boundary_scope.proj1.id
|
grant_scope_ids = [boundary_scope.proj1.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ resource "boundary_scope" "proj2" {
|
|||||||
|
|
||||||
resource "boundary_role" "proj2_admin" {
|
resource "boundary_role" "proj2_admin" {
|
||||||
scope_id = boundary_scope.org1.id
|
scope_id = boundary_scope.org1.id
|
||||||
grant_scope_id = boundary_scope.proj2.id
|
grant_scope_ids = [boundary_scope.proj2.id]
|
||||||
grant_strings = ["ids=*;type=*;actions=*"]
|
grant_strings = ["ids=*;type=*;actions=*"]
|
||||||
principal_ids = ["u_auth"]
|
principal_ids = ["u_auth"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
page_title: "boundary_worker Resource - terraform-provider-boundary"
|
||||||
|
subcategory: ""
|
||||||
|
description: |-
|
||||||
|
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
|
||||||
|
---
|
||||||
|
|
||||||
|
# boundary_worker (Resource)
|
||||||
|
|
||||||
|
{{ .Description | trimspace }}
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
### Controller-led worker
|
||||||
|
|
||||||
|
{{tffile "examples/resources/boundary_worker/controller_led.tf"}}
|
||||||
|
|
||||||
|
### Worker-led worker
|
||||||
|
|
||||||
|
{{tffile "examples/resources/boundary_worker/worker_led.tf"}}
|
||||||
|
|
||||||
|
{{ .SchemaMarkdown | trimspace }}
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Import is supported using the following syntax:
|
||||||
|
|
||||||
|
{{codefile "shell" "examples/resources/boundary_worker/import.sh" }}
|
||||||
Reference in new issue
Block a user