Copy Terraform provider from teleport-plugins repo (#40224)

* copy terraform provider

* Make dependecy checker happy + use go 1.22

* Run terraform tests in the CI, add Makefile target

* go mod tidy
This commit is contained in:
Hugo Shaka
2024-04-10 05:11:58 +00:00
committed by GitHub
parent 4e95c09b8f
commit d83cfd154c
183 changed files with 66659 additions and 7 deletions
+4 -1
View File
@@ -12,7 +12,10 @@ jobs:
pull-requests: write
with:
base-ref: ${{ github.event.pull_request.base.sha || 'master' }}
allow-ghsas: 'GHSA-xwh9-gc39-5298'
# 'GHSA-6xf3-5hp7-xqqg' is a false positive. That's an old Teleport Vuln,
# but because of the replace, the dependency cannot find the correct
# Teleport version.
allow-ghsas: 'GHSA-6xf3-5hp7-xqqg'
allow-dependencies-licenses: >-
pkg:cargo/curve25519-dalek-derive,
pkg:cargo/ring,
+1 -1
View File
@@ -79,7 +79,7 @@ jobs:
- name: Run base difftest
uses: ./.github/actions/difftest
with:
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" -e "integrations/operator/**/*" -e "tool/tsh/**/*" -e "integration/**/*" -e "build.assets/**/*" -e "lib/auth/webauthncli/**/*" -e "lib/auth/touchid/**/*" -e "api/**/*" -e "examples/teleport-usage/**/*" -e "integrations/access/**" -e "integrations/lib/**" -e "integrations/lib/backoff/backoff_test.go" -e "e2e/**/*"
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" -e "integrations/operator/**/*" -e "integrations/terraform/**/*" -e "tool/tsh/**/*" -e "integration/**/*" -e "build.assets/**/*" -e "lib/auth/webauthncli/**/*" -e "lib/auth/touchid/**/*" -e "api/**/*" -e "examples/teleport-usage/**/*" -e "integrations/access/**" -e "integrations/lib/**" -e "integrations/lib/backoff/backoff_test.go" -e "e2e/**/*"
target: test-go-unit
- name: Run touch-id difftest
@@ -67,6 +67,10 @@ jobs:
run: make test-integrations-lib
timeout-minutes: 5
- name: Run terraform provider OSS tests
run: make test-terraform-provider
timeout-minutes: 15
- name: Run operator tests
timeout-minutes: 40
run: make test-operator
+7 -1
View File
@@ -680,7 +680,7 @@ tooling: ensure-gotestsum $(DIFF_TEST)
# Runs all Go/shell tests, called by CI/CD.
#
.PHONY: test
test: test-helm test-sh test-api test-go test-rust test-operator
test: test-helm test-sh test-api test-go test-rust test-operator test-terraform-provider
$(TEST_LOG_DIR):
mkdir $(TEST_LOG_DIR)
@@ -821,6 +821,12 @@ test-api:
test-operator:
make -C integrations/operator test
#
# Runs Teleport Terraform provider tests.
#
.PHONY: test-terraform-provider
test-terraform-provider:
make -C integrations/terraform test
#
# Runs Go tests on the integrations/kube-agent-updater module. These have to be run separately as the package name is different.
#
.PHONY: test-kube-agent-updater
@@ -44,7 +44,10 @@ import (
// integration tests to build teleport clients for each user/plugin/bot.
type OSSAuthHelper struct {
server *libauth.TestTLSServer
dir string
// dir is where we put identity files, and start the auth server
// (unless AuthConfig.Dir is manually set).
dir string
AuthConfig libauth.TestAuthServerConfig
}
// StartServer implements the AuthHelper interface.
@@ -52,9 +55,10 @@ type OSSAuthHelper struct {
// on the t.Cleanup() stack.
func (a *OSSAuthHelper) StartServer(t *testing.T) *client.Client {
a.dir = t.TempDir()
authServer, err := libauth.NewTestAuthServer(libauth.TestAuthServerConfig{
Dir: a.dir,
})
if a.AuthConfig.Dir == "" {
a.AuthConfig.Dir = a.dir
}
authServer, err := libauth.NewTestAuthServer(a.AuthConfig)
require.NoError(t, err)
t.Cleanup(func() {
+14
View File
@@ -0,0 +1,14 @@
# Build artifacts
build/*
# Terraform state
.terraform
*.tfstate*
*.lock.hcl
example/vars.tfvars
example/*.tf
tmp
*.swp
*.log
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+132
View File
@@ -0,0 +1,132 @@
include install.mk
LOCALDIR := $(dir $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
GENTERRAFORMPATH := $(shell go env GOPATH)/bin
BUILDDIR ?= build
TFDIR ?= example
ADDFLAGS ?=
BUILDFLAGS ?= $(ADDFLAGS) -ldflags '-w -s'
CGOFLAG ?= CGO_ENABLED=0
RELEASE = terraform-provider-teleport-v$(VERSION)-$(OS)-$(ARCH)-bin
.PHONY: tfclean
tfclean:
rm -rf $(TFDIR)/terraform.tfstate
rm -rf $(TFDIR)/terraform.tfstate.backup
rm -rf $(TFDIR)/.terraform
rm -rf $(TFDIR)/.terraform.lock.hcl
.PHONY: clean
clean: tfclean
rm -rf $(PROVIDER_PATH)*
rm -rf $(BUILDDIR)/*
rm -rf $(RELEASE).tar.gz
go clean
.PHONY: build
build: clean
GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -o $(BUILDDIR)/terraform-provider-teleport $(BUILDFLAGS)
build-darwin-universal: $(addprefix $(BUILDDIR)/terraform-provider-teleport_,arm64 amd64)
lipo -create -output $(BUILDDIR)/terraform-provider-teleport $^
rm -r $^ $(BUILDDIR)/$(OS)
# Architecture-specific binaries for the universal binary are extracted from
# the release tarball. make will not automatically build this; you will need
# to run "make ARCH=amd64 release" and "make ARCH=arm64 release" first as is
# done in the build workflow.
$(BUILDDIR)/terraform-provider-teleport_%: terraform-provider-teleport-v$(VERSION)-$(OS)-%-bin.tar.gz
mkdir -p $(BUILDDIR)/$(OS)/$*
tar -xzf $< -C $(BUILDDIR)/$(OS)/$*
mv $(BUILDDIR)/$(OS)/$*/terraform-provider-teleport $@
CUSTOM_IMPORTS_TMP_DIR ?= /tmp/protoc-gen-terraform/custom-imports
PROTOC_GEN_TERRAFORM_VERSION ?= v2.1.0
PROTOC_GEN_TERRAFORM_EXISTS := $(shell protoc-gen-terraform version 2>&1 >/dev/null | grep 'protoc-gen-terraform $(PROTOC_GEN_TERRAFORM_VERSION)')
.PHONY: gen-tfschema
gen-tfschema:
ifndef PROTOC_GEN_TERRAFORM_EXISTS
@echo "protoc-gen-terraform $(PROTOC_GEN_TERRAFORM_VERSION) is not installed. Please, refer to README.md for installation instructions."
@exit -1
endif
# The wrappers.proto file needed for this generator exist only inside the go mod cache,
# so we retrieve the file path for the cached proto files with go mod tools.
$(eval PROTOBUF_MOD_PATH := $(shell go mod download --json github.com/gogo/protobuf | jq .Dir))
@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
--plugin=$(GENTERRAFORMPATH)/protoc-gen-terraform \
--terraform_out=config=protoc-gen-terraform-teleport.yaml:./tfschema \
teleport/legacy/types/types.proto
@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
--plugin=$(GENTERRAFORMPATH)/protoc-gen-terraform \
--terraform_out=config=protoc-gen-terraform-loginrule.yaml:./tfschema \
teleport/loginrule/v1/loginrule.proto
@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
--plugin=$(GENTERRAFORMPATH)/protoc-gen-terraform \
--terraform_out=config=protoc-gen-terraform-devicetrust.yaml:./tfschema \
teleport/legacy/types/device.proto
@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
--plugin=$(GENTERRAFORMPATH)/protoc-gen-terraform \
--terraform_out=config=protoc-gen-terraform-accesslist.yaml:./tfschema \
teleport/accesslist/v1/accesslist.proto
mv ./tfschema/github.com/gravitational/teleport/api/types/types_terraform.go ./tfschema/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1/loginrule_terraform.go ./tfschema/loginrule/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1/accesslist_terraform.go ./tfschema/accesslist/v1/
mv ./tfschema/github.com/gravitational/teleport/api/types/device_terraform.go ./tfschema/devicetrust/v1/
rm -r ./tfschema/github.com/
@go run ./gen/main.go
@go run ./gen/main.go docs
.PHONY: release
ifeq ($(OS)-$(ARCH),darwin-universal)
release: build-darwin-universal
else
release: build
endif
tar -C $(BUILDDIR) -czf $(RELEASE).tar.gz .
TERRAFORM_EXISTS := $(shell terraform -version 2>/dev/null | grep 'Terraform v1.')
CURRENT_ULIMIT := $(shell ulimit -n)
.PHONY: test
test: install
ifndef TERRAFORM_EXISTS
@echo "Terraform v1.4+ is not installed (tfenv install 1.5.6 && tfenv use 1.5.6)."
terraform -version
@exit -1
endif
# NOTE: This is related to an old bug in Terraform and will be fixed in future releases (possibly, by a workaround on our side)
ifeq ($(shell expr $(CURRENT_ULIMIT) \< 1024), 1)
@echo "ulimit -n is too low ($(CURRENT_ULIMIT)), please set ulimit -n 1024"
@exit -1
endif
TF_ACC=true go test ./test -v
.PHONY: apply
apply: install
terraform -chdir=$(TFDIR) init && terraform -chdir=$(TFDIR) apply -auto-approve
.PHONY: reapply
reapply:
terraform -chdir=$(TFDIR) apply
.PHONY: destroy
destroy:
terraform -chdir=$(TFDIR) destroy -auto-approve
+95
View File
@@ -0,0 +1,95 @@
# Terraform Provider Plugin
## Usage
Please, refer to [official documentation](https://goteleport.com/docs/setup/guides/terraform-provider/).
## Development
1. Install [`protobuf`](https://grpc.io/docs/protoc-installation/).
2. Install [`protoc-gen-terraform`](https://github.com/gravitational/protoc-gen-terraform).
```go install github.com/gravitational/protoc-gen-terraform@main```
3. Install [`Terraform`](https://learn.hashicorp.com/tutorials/terraform/install-cli) v1.1.0+. Alternatively, you can use [`tfenv`](https://github.com/tfutils/tfenv). Please note that on Mac M1 you need to specify `TFENV_ARCH` (ex: `TFENV_ARCH=arm64 tfenv install 1.1.6`).
4. Clone the plugin:
```bash
git clone [email protected]:gravitational/teleport-plugins
```
5. Build and install the plugin:
```bash
cd teleport-plugins/terraform
make install
```
6. Run tests:
```bash
make test
```
Note: Some tests won't pass without a valid `teleport` binary, enterprise license, etc.
See [Testing](../TESTING.md) to see how to provide these values to the tests locally.
# Updating the provider
Run:
```
make gen-tfschema
```
This will generate `types_tfschema.go` from a current API `.proto` file, and regenerate the provider code.
# Playing with examples locally
1. Start Teleport.
```
teleport start
```
1. Create Terraform user and role:
```
tctl create example/terraform.yaml
tctl auth sign --format=file --user=terraform --out=/tmp/terraform-identity --ttl=10h
```
1. Create `main.tf` file:
```
cp example/main.tf.example example/main.tf
```
Please note that target identity file was exported to `/tmp/terraform-identity` on previous step. If you used another location, please change in in `main.tf`.
1. Create sample resources:
```
cp example/user.tf.example example/user.tf
cp example/role.tf.example example/role.tf
cp example/provision_token.tf.example example/provision_token.tf
```
Please note that some resources require preliminary setup steps.
1. Apply changes:
```
make apply
```
1. Make changes to .tf files and run:
```
make reapply
```
1. Clean up:
```
make destroy
```
@@ -0,0 +1,39 @@
resource "teleport_access_list" "crane-operation" {
header = {
metadata = {
name = "crane-operation"
labels = {
example = "yes"
}
}
}
spec = {
description = "Used to grant access to the crane."
owners = [
{
name = "gru"
description = "The supervillain."
}
]
membership_requires = {
roles = ["minion"]
}
ownership_requires = {
roles = ["supervillain"]
}
grants = {
roles = ["crane-operator"]
traits = [{
key = "allowed-machines"
values = ["crane", "forklift"]
}]
}
title = "Crane operation"
audit = {
recurrence = {
frequency = 3 # audit every 3 months
day_of_month = 15 # audit happen 15's day of the month. Possible values are 1, 15, and 31.
}
}
}
}
@@ -0,0 +1,15 @@
# Teleport App
resource "teleport_app" "example" {
metadata = {
name = "example"
description = "Test app"
labels = {
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
uri = "localhost:3000"
}
}
@@ -0,0 +1,15 @@
# AuthPreference resource
resource "teleport_auth_preference" "example" {
metadata = {
description = "Auth preference"
labels = {
"example" = "yes"
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
disconnect_expired_cert = true
}
}
@@ -0,0 +1,35 @@
# Teleport Machine ID Bot creation example
locals {
bot_name = "example"
}
resource "random_password" "bot_token" {
length = 32
special = false
}
resource "time_offset" "bot_example_token_expiry" {
offset_hours = 1
}
resource "teleport_provision_token" "bot_example" {
metadata = {
expires = time_offset.bot_example_token_expiry.rfc3339
description = "Bot join token for ${local.bot_name} generated by Terraform"
name = random_password.bot_token.result
}
spec = {
roles = ["Bot"]
bot_name = local.bot_name
join_method = "token"
}
}
resource "teleport_bot" "example" {
name = local.bot_name
token_id = teleport_provision_token.bot_example.metadata.name
roles = ["access"]
}
@@ -0,0 +1,14 @@
# Teleport Cluster Networking config
resource "teleport_cluster_maintenance_config" "example" {
metadata = {
description = "Maintenance config"
}
spec = {
agent_upgrades = {
utc_start_hour = 1
weekdays = [ "monday" ]
}
}
}
@@ -0,0 +1,15 @@
# Teleport Cluster Networking config
resource "teleport_cluster_networking_config" "example" {
metadata = {
description = "Networking config"
labels = {
"example" = "yes"
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
client_idle_timeout = "1h"
}
}
@@ -0,0 +1,16 @@
# Teleport Database
resource "teleport_database" "example" {
metadata = {
name = "example"
description = "Test database"
labels = {
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
protocol = "postgres"
uri = "localhost"
}
}
@@ -0,0 +1,28 @@
# Terraform Github connector
variable "github_secret" {}
resource "teleport_github_connector" "github" {
# This section tells Terraform that role example must be created before the GitHub connector
depends_on = [
teleport_role.example
]
metadata = {
name = "example"
labels = {
example = "yes"
}
}
spec = {
client_id = "client"
client_secret = var.github_secret
teams_to_roles = [{
organization = "gravitational"
team = "devs"
roles = ["example"]
}]
}
}
@@ -0,0 +1,26 @@
# Teleport Login Rule resource
resource "teleport_login_rule" "example" {
metadata = {
description = "Example Login Rule"
labels = {
"example" = "yes"
}
}
version = "v1"
priority = 0
traits_map = {
"logins" = {
values = [
"external.logins",
"external.username",
]
}
"groups" = {
values = [
"external.groups",
]
}
}
}
@@ -0,0 +1,17 @@
terraform {
required_providers {
teleport = {
version = "9.1.3"
source = "terraform.releases.teleport.dev/gravitational/teleport"
}
}
}
# Terraform Provider configuration. See provider.go for available options
provider "teleport" {
# Path to Teleport identity file
identity_file_path = "/tmp/terraform-identity"
# Teleport proxy addr
addr = "teleport.example.com:443"
}
@@ -0,0 +1,27 @@
# Teleport OIDC connector
#
# Please note that OIDC connector will work in Enterprise version only. Check the setup docs:
# https://goteleport.com/docs/enterprise/sso/oidc/
variable "oidc_secret" {}
resource "teleport_oidc_connector" "example" {
metadata = {
name = "example"
labels = {
test = "yes"
}
}
spec = {
client_id = "client"
client_secret = var.oidc_secret
claims_to_roles = [{
claim = "test"
roles = ["terraform"]
}]
redirect_url = ["https://example.com/redirect"]
}
}
@@ -0,0 +1,58 @@
# Teleport Okta Import Rule resource
resource "teleport_okta_import_rule" "example" {
metadata = {
description = "Example Okta Import Rule"
labels = {
"example" = "yes"
}
}
version = "v1"
spec = {
priority = 100
mappings = [
{
add_labels = {
"label1": "value1"
}
match = [
{
app_ids = ["1", "2", "3"]
},
],
},
{
add_labels = {
"label2": "value2"
}
match = [
{
group_ids = ["1", "2", "3"]
},
],
},
{
add_labels = {
"label3" : "value3",
}
match = [
{
group_name_regexes = ["^.*$"]
},
],
},
{
add_labels = {
"label4" : "value4",
}
match = [
{
app_name_regexes = ["^.*$"]
},
],
}
]
}
}
@@ -0,0 +1,31 @@
# Teleport Provision Token resource
resource "teleport_provision_token" "example" {
metadata = {
expires = "2022-10-12T07:20:51Z"
description = "Example token"
labels = {
example = "yes"
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
roles = ["Node", "Auth"]
}
}
resource "teleport_provision_token" "iam-token" {
metadata = {
name = "iam-token"
}
spec = {
roles = ["Bot"]
bot_name = "mybot"
join_method = "iam"
allow = [{
aws_account = "123456789012"
}]
}
}
@@ -0,0 +1,50 @@
# Teleport Role resource
resource "teleport_role" "example" {
metadata = {
name = "example"
description = "Example Teleport Role"
expires = "2022-10-12T07:20:51Z"
labels = {
example = "yes"
}
}
spec = {
options = {
forward_agent = false
max_session_ttl = "7m"
port_forwarding = false
client_idle_timeout = "1h"
disconnect_expired_cert = true
permit_x11_forwarding = false
request_access = "denied"
}
allow = {
logins = ["example"]
rules = [{
resources = ["user", "role"]
verbs = ["list"]
}]
request = {
roles = ["example"]
claims_to_roles = [{
claim = "example"
value = "example"
roles = ["example"]
}]
}
node_labels = {
example = ["yes"]
}
}
deny = {
logins = ["anonymous"]
}
}
}
@@ -0,0 +1,43 @@
# Teleport SAML connector
#
# Please note that SAML connector will work in Enterprise version only. Check the setup docs:
# https://goteleport.com/docs/enterprise/sso/okta/
resource "teleport_saml_connector" "example" {
# This block will tell Terraform to never update private key from our side if a keys are managed
# from an outside of Terraform.
# lifecycle {
# ignore_changes = [
# spec[0].signing_key_pair[0].cert,
# spec[0].signing_key_pair[0].private_key,
# spec[0].assertion_key_pair[0].cert,
# spec[0].assertion_key_pair[0].private_key,
# ]
# }
# This section tells Terraform that role example must be created before the SAML connector
depends_on = [
teleport_role.example
]
metadata = {
name = "example"
}
spec = {
attributes_to_roles = [{
name = "groups"
roles = ["example"]
value = "okta-admin"
},
{
name = "groups"
roles = ["example"]
value = "okta-dev"
}]
acs = "https://localhost:3025/v1/webapi/saml/acs"
entity_descriptor = ""
}
}
@@ -0,0 +1,43 @@
resource "teleport_server" "ssh_agentless" {
version = "v2"
sub_kind = "openssh"
// Name is not required for servers, this is a special case.
// When a name is not set, an UUID will be generated by Teleport and
// imported back into Terraform.
// Giving unique IDs to servers allows UUID-based dialing (as opposed to
// host-based dialing and IP-based dialing) which is more robust than its
// counterparts as it can point to a specific server if multiple servers
// share the same hostname/ip.
spec = {
addr = "127.0.0.1:22"
hostname = "test.local"
}
}
resource "teleport_server" "ssh_agentless_eice" {
version = "v2"
sub_kind = "openssh-ec2-ice"
metadata = {
// It is recommended to put the account and instance ID as a name for EC2 Instance Connect
// When dialing to this instance, teleport will detect that this is an
// AWS instance ID an will contact this specific instance. This is more
// robust than host-based and IP-based dialing (because several server
// can have similar hostnames).
name = "123456789012-i-0123456789abcdef"
}
spec = {
addr = "127.0.0.1:22"
hostname = "test.local"
cloud_metadata = {
aws = {
account_id = "123"
instance_id = "123"
region = "us-east-1"
vpc_id = "123"
integration = "foo"
subnet_id = "123"
}
}
}
}
@@ -0,0 +1,15 @@
# Teleport session recording config
resource "teleport_session_recording_config" "example" {
metadata = {
description = "Session recording config"
labels = {
"example" = "yes"
"teleport.dev/origin" = "dynamic" // This label is added on Teleport side by default
}
}
spec = {
proxy_checks_host_keys = true
}
}
@@ -0,0 +1,40 @@
kind: role
metadata:
name: terraform
spec:
allow:
app_labels: # This gives Terraform access to all apps in the cluster. You might want to restrict it.
'*': '*'
db_labels: # This gives Terraform access to all databases in the cluster. You might want to restrict it.
'*': '*'
db_users: ['*']
db_names: ['*']
rules:
- resources:
- user
- role
- token
- trusted_cluster
- github
- oidc
- saml
- cluster_auth_preference
- cluster_networking_config
- cluster_maintenance_config
- session_recording_config
- app
- db
- login_rule
- device
- okta_import_rule
- access_list
verbs: ['list','create','read','update','delete']
version: v6
---
kind: user
metadata:
name: terraform
spec:
roles: ['terraform']
version: v2
@@ -0,0 +1,22 @@
# Teleport trusted cluster
#
# https://goteleport.com/docs/setup/admin/trustedclusters/
resource "teleport_trusted_cluster" "cluster" {
metadata = {
name = "primary"
labels = {
test = "yes"
}
}
spec = {
enabled = false
role_map = [{
remote = "test"
local = ["admin"]
}]
proxy_addr = "localhost:3080"
token = "salami"
}
}
@@ -0,0 +1,8 @@
# Trusted device resource
resource "teleport_trusted_device" "TESTDEVICE1" {
spec = {
asset_tag = "TESTDEVICE1"
os_type = "macos"
}
}
@@ -0,0 +1,43 @@
# Teleport User resource
resource "teleport_user" "example" {
# Tells Terraform that the role could not be destroyed while this user exists
depends_on = [
teleport_role.example
]
metadata = {
name = "example"
description = "Example Teleport User"
expires = "2022-10-12T07:20:50Z"
labels = {
example = "yes"
}
}
spec = {
roles = ["example"]
oidc_identities = [{
connector_id = "oidc1"
username = "example"
}]
traits = {
"logins1" = ["example"]
"logins2" = ["example"]
}
github_identities = [{
connector_id = "github"
username = "example"
}]
saml_identities = [{
connector_id = "example-saml"
username = "example"
}]
}
}
+732
View File
@@ -0,0 +1,732 @@
// Copyright 2023 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
"context"
_ "embed"
"fmt"
"io"
"log"
"os"
"path"
"sort"
"strings"
"text/template"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/olekukonko/tablewriter"
"golang.org/x/exp/slices"
"github.com/gravitational/teleport/integrations/terraform/provider"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
accesslistSchema "github.com/gravitational/teleport/integrations/terraform/tfschema/accesslist/v1"
devicetrustSchema "github.com/gravitational/teleport/integrations/terraform/tfschema/devicetrust/v1"
loginruleSchema "github.com/gravitational/teleport/integrations/terraform/tfschema/loginrule/v1"
)
// payload represents template payload
type payload struct {
// Name represents resource name (capitalized)
Name string
// VarName represents resource variable name (underscored)
VarName string
// TypeName represents api/types resource type name
TypeName string
// IfaceName represents api/types interface for the (usually this is the same as Name)
IfaceName string
// GetMethod represents API get method name
GetMethod string
// CreateMethod represents API create method name
CreateMethod string
// CreateMethod represents API update method name
UpdateMethod string
// DeleteMethod represents API reset method used in singular resources
DeleteMethod string
// UpsertMethodArity represents Create/Update method arity, if it's 2, then the call signature would be "_, err :="
UpsertMethodArity int
// WithSecrets value for a withSecrets param of Get method (empty means no param used)
WithSecrets string
// ID id value on create and import
ID string
// RandomMetadataName indicates that Metadata.Name must be generated (supported by plural resources only)
RandomMetadataName bool
// UUIDMetadataName functions similar to RandomMetadataName but generates UUID instead of
// generating 32 bit crypto random value
UUIDMetadataName bool
// Kind Teleport kind for a resource
Kind string
// DefaultVersion represents the default resource version on create
DefaultVersion string
// HasStaticID states whether this particular resource has a static (usually 0) Metadata.ID
// This is relevant to cache enabled clusters: we use Metadata.ID to check if the resource was updated
// Currently, the resources that don't have a dynamic Metadata.ID are strong consistent: oidc, github and saml connectors
HasStaticID bool
// ProtoPackagePath is the path of the package where the protobuf type of
// the resource is defined.
ProtoPackagePath string
// ProtoPackagePath is the name of the package where the protobuf type of
// the resource is defined.
ProtoPackage string
// SchemaPackagePath is the path of the package where the resource schema
// definitions are defined.
SchemaPackagePath string
// SchemaPackagePath is the name of the package where the resource schema
// definitions are defined.
SchemaPackage string
// IsPlainStruct states whether the resource type used by the API methods
// for this resource is a plain struct, rather than an interface.
IsPlainStruct bool
// HasCheckAndSetDefaults indicates whether the resource type has the CheckAndSetDefaults method
HasCheckAndSetDefaults bool
// ExtraImports contains a list of imports that are being used.
ExtraImports []string
// TerraformResourceType represents the resource type in Terraform code.
// e.g. `terraform import <resource_type>.<resource_name> identifier`.
// This is also used to name the generated files.
TerraformResourceType string
// WithNonce is used to force upsert behavior for nonce protected values.
WithNonce bool
// ConvertPackagePath is the path of the package doing the conversion between protobuf and the go types.
ConvertPackagePath string
// PropagatedFields is a list of fields that must be copied from the
// existing resource when we're updating it. For example:
// "Spec.Audit.NextAuditDate" in AccessList resource
PropagatedFields []string
// Namespaced indicates that the resource get and delete methods need the
// deprecated namespace parameter (always the default namespace).
Namespaced bool
// ForceSetKind indicates that the resource kind must be forcefully set by the provider.
// This is required for some special resources (ServerV2) that support multiple kinds.
// For those resources, we must set the kind, and don't want to have the user do it.
ForceSetKind string
// GetCanReturnNil is used to check for nil returned value when doing a Get<Resource>.
GetCanReturnNil bool
}
func (p *payload) CheckAndSetDefaults() error {
if p.ProtoPackage == "" {
p.ProtoPackage = "apitypes"
}
if p.ProtoPackagePath == "" {
p.ProtoPackagePath = "github.com/gravitational/teleport/api/types"
}
if p.SchemaPackage == "" {
p.SchemaPackage = "tfschema"
}
if p.SchemaPackagePath == "" {
p.SchemaPackagePath = "github.com/gravitational/teleport/integrations/terraform/tfschema"
}
return nil
}
const (
pluralResource = "plural_resource.go.tpl"
pluralDataSource = "plural_data_source.go.tpl"
singularResource = "singular_resource.go.tpl"
singularDataSource = "singular_data_source.go.tpl"
outFileResourceFormat = "provider/resource_%s.go"
outFileDataSourceFormat = "provider/data_source_%s.go"
referenceDocsTemplate = "referencedocs.go.tpl"
)
var (
app = payload{
Name: "App",
TypeName: "AppV3",
VarName: "app",
IfaceName: "Application",
GetMethod: "GetApp",
CreateMethod: "CreateApp",
UpdateMethod: "UpdateApp",
DeleteMethod: "DeleteApp",
ID: `app.Metadata.Name`,
Kind: "app",
HasStaticID: false,
TerraformResourceType: "teleport_app",
HasCheckAndSetDefaults: true,
}
authPreference = payload{
Name: "AuthPreference",
TypeName: "AuthPreferenceV2",
VarName: "authPreference",
GetMethod: "GetAuthPreference",
CreateMethod: "SetAuthPreference",
UpdateMethod: "SetAuthPreference",
DeleteMethod: "ResetAuthPreference",
ID: `"auth_preference"`,
Kind: "cluster_auth_preference",
HasStaticID: false,
TerraformResourceType: "teleport_auth_preference",
HasCheckAndSetDefaults: true,
}
clusterMaintenance = payload{
Name: "ClusterMaintenanceConfig",
TypeName: "ClusterMaintenanceConfigV1",
VarName: "clusterMaintenanceConfig",
GetMethod: "GetClusterMaintenanceConfig",
CreateMethod: "UpdateClusterMaintenanceConfig",
UpdateMethod: "UpdateClusterMaintenanceConfig",
DeleteMethod: "DeleteClusterMaintenanceConfig",
ID: `"cluster_maintenance_config"`,
Kind: "cluster_maintenance_config",
HasStaticID: true,
TerraformResourceType: "teleport_cluster_maintenance_config",
WithNonce: true,
GetCanReturnNil: true,
HasCheckAndSetDefaults: true,
}
clusterNetworking = payload{
Name: "ClusterNetworkingConfig",
TypeName: "ClusterNetworkingConfigV2",
VarName: "clusterNetworkingConfig",
GetMethod: "GetClusterNetworkingConfig",
CreateMethod: "SetClusterNetworkingConfig",
UpdateMethod: "SetClusterNetworkingConfig",
DeleteMethod: "ResetClusterNetworkingConfig",
ID: `"cluster_networking_config"`,
Kind: "cluster_networking_config",
HasStaticID: false,
TerraformResourceType: "teleport_cluster_networking_config",
HasCheckAndSetDefaults: true,
}
database = payload{
Name: "Database",
TypeName: "DatabaseV3",
VarName: "database",
GetMethod: "GetDatabase",
CreateMethod: "CreateDatabase",
UpdateMethod: "UpdateDatabase",
DeleteMethod: "DeleteDatabase",
ID: `database.Metadata.Name`,
Kind: "db",
HasStaticID: false,
TerraformResourceType: "teleport_database",
HasCheckAndSetDefaults: true,
}
githubConnector = payload{
Name: "GithubConnector",
TypeName: "GithubConnectorV3",
VarName: "githubConnector",
GetMethod: "GetGithubConnector",
CreateMethod: "CreateGithubConnector",
UpdateMethod: "UpsertGithubConnector",
UpsertMethodArity: 2,
DeleteMethod: "DeleteGithubConnector",
WithSecrets: "true",
ID: "githubConnector.Metadata.Name",
Kind: "github",
HasStaticID: true,
TerraformResourceType: "teleport_github_connector",
HasCheckAndSetDefaults: true,
}
oidcConnector = payload{
Name: "OIDCConnector",
TypeName: "OIDCConnectorV3",
VarName: "oidcConnector",
GetMethod: "GetOIDCConnector",
CreateMethod: "CreateOIDCConnector",
UpdateMethod: "UpsertOIDCConnector",
UpsertMethodArity: 2,
DeleteMethod: "DeleteOIDCConnector",
WithSecrets: "true",
ID: "oidcConnector.Metadata.Name",
Kind: "oidc",
HasStaticID: true,
TerraformResourceType: "teleport_oidc_connector",
HasCheckAndSetDefaults: true,
}
samlConnector = payload{
Name: "SAMLConnector",
TypeName: "SAMLConnectorV2",
VarName: "samlConnector",
GetMethod: "GetSAMLConnector",
CreateMethod: "CreateSAMLConnector",
UpdateMethod: "UpsertSAMLConnector",
UpsertMethodArity: 2,
DeleteMethod: "DeleteSAMLConnector",
WithSecrets: "true",
ID: "samlConnector.Metadata.Name",
Kind: "saml",
HasStaticID: true,
TerraformResourceType: "teleport_saml_connector",
HasCheckAndSetDefaults: true,
}
provisionToken = payload{
Name: "ProvisionToken",
TypeName: "ProvisionTokenV2",
VarName: "provisionToken",
GetMethod: "GetToken",
CreateMethod: "UpsertToken",
UpdateMethod: "UpsertToken",
DeleteMethod: "DeleteToken",
ID: "strconv.FormatInt(provisionToken.Metadata.ID, 10)", // must be a string
RandomMetadataName: true,
Kind: "token",
HasStaticID: false,
ExtraImports: []string{"strconv"},
TerraformResourceType: "teleport_provision_token",
HasCheckAndSetDefaults: true,
}
role = payload{
Name: "Role",
TypeName: "RoleV6",
VarName: "role",
GetMethod: "GetRole",
CreateMethod: "CreateRole",
UpdateMethod: "UpsertRole",
UpsertMethodArity: 2,
DeleteMethod: "DeleteRole",
ID: "role.Metadata.Name",
Kind: "role",
HasStaticID: false,
TerraformResourceType: "teleport_role",
HasCheckAndSetDefaults: true,
}
sessionRecording = payload{
Name: "SessionRecordingConfig",
TypeName: "SessionRecordingConfigV2",
VarName: "sessionRecordingConfig",
GetMethod: "GetSessionRecordingConfig",
CreateMethod: "SetSessionRecordingConfig",
UpdateMethod: "SetSessionRecordingConfig",
DeleteMethod: "ResetSessionRecordingConfig",
ID: `"session_recording_config"`,
Kind: "session_recording_config",
HasStaticID: false,
TerraformResourceType: "teleport_session_recording_config",
HasCheckAndSetDefaults: true,
}
trustedCluster = payload{
Name: "TrustedCluster",
TypeName: "TrustedClusterV2",
VarName: "trustedCluster",
GetMethod: "GetTrustedCluster",
CreateMethod: "UpsertTrustedCluster",
UpdateMethod: "UpsertTrustedCluster",
DeleteMethod: "DeleteTrustedCluster",
UpsertMethodArity: 2,
ID: "trustedCluster.Metadata.Name",
Kind: "trusted_cluster",
HasStaticID: false,
TerraformResourceType: "teleport_trusted_cluster",
HasCheckAndSetDefaults: true,
}
user = payload{
Name: "User",
TypeName: "UserV2",
VarName: "user",
GetMethod: "GetUser",
CreateMethod: "CreateUser",
UpdateMethod: "UpsertUser",
UpsertMethodArity: 2,
DeleteMethod: "DeleteUser",
WithSecrets: "false",
ID: "user.Metadata.Name",
Kind: "user",
HasStaticID: false,
TerraformResourceType: "teleport_user",
HasCheckAndSetDefaults: true,
}
loginRule = payload{
Name: "LoginRule",
TypeName: "LoginRule",
VarName: "loginRule",
GetMethod: "GetLoginRule",
CreateMethod: "UpsertLoginRule",
UpsertMethodArity: 2,
UpdateMethod: "UpsertLoginRule",
DeleteMethod: "DeleteLoginRule",
ID: "loginRule.Metadata.Name",
Kind: "login_rule",
HasStaticID: true,
ProtoPackage: "loginrulev1",
ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1",
SchemaPackage: "schemav1",
SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/loginrule/v1",
IsPlainStruct: true,
TerraformResourceType: "teleport_login_rule",
}
deviceTrust = payload{
Name: "DeviceV1",
VarName: "trustedDevice",
TypeName: "DeviceV1",
GetMethod: "GetDeviceResource",
CreateMethod: "UpsertDeviceResource",
UpsertMethodArity: 2,
UpdateMethod: "UpsertDeviceResource",
DeleteMethod: "DeleteDeviceResource",
Kind: "device",
ID: "trustedDevice.Metadata.Name",
HasStaticID: true,
SchemaPackage: "schemav1",
SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/devicetrust/v1",
IsPlainStruct: true,
UUIDMetadataName: true,
TerraformResourceType: "teleport_device_trust",
}
oktaImportRule = payload{
Name: "OktaImportRule",
TypeName: "OktaImportRuleV1",
VarName: "oktaImportRule",
IfaceName: "OktaImportRule",
GetMethod: "OktaClient().GetOktaImportRule",
CreateMethod: "OktaClient().CreateOktaImportRule",
UpdateMethod: "OktaClient().UpdateOktaImportRule",
DeleteMethod: "OktaClient().DeleteOktaImportRule",
UpsertMethodArity: 2,
ID: "oktaImportRule.Metadata.Name",
Kind: "okta_import_rule",
HasStaticID: false,
TerraformResourceType: "teleport_okta_import_rule",
HasCheckAndSetDefaults: true,
}
accessList = payload{
Name: "AccessList",
TypeName: "AccessList",
VarName: "accessList",
GetMethod: "AccessListClient().GetAccessList",
CreateMethod: "AccessListClient().UpsertAccessList",
UpsertMethodArity: 2,
UpdateMethod: "AccessListClient().UpsertAccessList",
DeleteMethod: "AccessListClient().DeleteAccessList",
ID: "accessList.Header.Metadata.Name",
Kind: "access_list",
HasStaticID: false,
SchemaPackage: "schemav1",
SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/accesslist/v1",
ProtoPackage: "accesslist",
ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1",
TerraformResourceType: "teleport_access_list",
ConvertPackagePath: "github.com/gravitational/teleport/api/types/accesslist/convert/v1",
HasCheckAndSetDefaults: true,
PropagatedFields: []string{"Spec.Audit.NextAuditDate"},
}
server = payload{
Name: "Server",
TypeName: "ServerV2",
VarName: "server",
GetMethod: "GetNode",
CreateMethod: "UpsertNode",
UpdateMethod: "UpsertNode",
UpsertMethodArity: 2,
DeleteMethod: "DeleteNode",
ID: "server.Metadata.Name",
Kind: "node",
HasStaticID: false,
TerraformResourceType: "teleport_server",
HasCheckAndSetDefaults: true,
Namespaced: true,
ForceSetKind: "apitypes.KindNode",
}
)
func main() {
if len(os.Args) == 2 && os.Args[1] == "docs" {
genReferenceDocs()
} else {
genTFSchema()
}
}
func genTFSchema() {
generateResource(app, pluralResource)
generateDataSource(app, pluralDataSource)
generateResource(authPreference, singularResource)
generateDataSource(authPreference, singularDataSource)
generateResource(clusterMaintenance, singularResource)
generateDataSource(clusterMaintenance, singularDataSource)
generateResource(clusterNetworking, singularResource)
generateDataSource(clusterNetworking, singularDataSource)
generateResource(database, pluralResource)
generateDataSource(database, pluralDataSource)
generateResource(githubConnector, pluralResource)
generateDataSource(githubConnector, pluralDataSource)
generateResource(oidcConnector, pluralResource)
generateDataSource(oidcConnector, pluralDataSource)
generateResource(samlConnector, pluralResource)
generateDataSource(samlConnector, pluralDataSource)
generateResource(provisionToken, pluralResource)
generateDataSource(provisionToken, pluralDataSource)
generateResource(role, pluralResource)
generateDataSource(role, pluralDataSource)
generateResource(trustedCluster, pluralResource)
generateDataSource(trustedCluster, pluralDataSource)
generateResource(sessionRecording, singularResource)
generateDataSource(sessionRecording, singularDataSource)
generateResource(user, pluralResource)
generateDataSource(user, pluralDataSource)
generateResource(loginRule, pluralResource)
generateDataSource(loginRule, pluralDataSource)
generateResource(deviceTrust, pluralResource)
generateDataSource(deviceTrust, pluralDataSource)
generateResource(oktaImportRule, pluralResource)
generateDataSource(oktaImportRule, pluralDataSource)
generateResource(accessList, pluralResource)
generateDataSource(accessList, pluralDataSource)
generateResource(server, pluralResource)
generateDataSource(server, pluralDataSource)
}
func generateResource(p payload, tpl string) {
outFile := fmt.Sprintf(outFileResourceFormat, p.TerraformResourceType)
generate(p, tpl, outFile)
}
func generateDataSource(p payload, tpl string) {
outFile := fmt.Sprintf(outFileDataSourceFormat, p.TerraformResourceType)
generate(p, tpl, outFile)
}
func generate(p payload, tpl, outFile string) {
if err := p.CheckAndSetDefaults(); err != nil {
log.Fatal(err)
}
funcs := template.FuncMap{
"schemaImport": func(p payload) string {
if p.SchemaPackage == "tfschema" {
return `"` + p.SchemaPackagePath + `"`
}
return p.SchemaPackage + ` "` + p.SchemaPackagePath + `"`
},
"protoImport": func(p payload) string {
if p.ConvertPackagePath != "" {
return "convert" + ` "` + p.ConvertPackagePath + `"`
}
return p.ProtoPackage + ` "` + p.ProtoPackagePath + `"`
},
}
t, err := template.New(p.Name).Funcs(funcs).ParseFiles(path.Join("gen", tpl))
if err != nil {
log.Fatal(err)
}
var b bytes.Buffer
err = t.ExecuteTemplate(&b, tpl, p)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile(outFile, b.Bytes(), 0777)
if err != nil {
log.Fatal(err)
}
}
// Create Docs Markdown
var (
mapResourceSchema = map[string]func(context.Context) (tfsdk.Schema, diag.Diagnostics){
"access_list": accesslistSchema.GenSchemaAccessList,
"app": tfschema.GenSchemaAppV3,
"auth_preference": tfschema.GenSchemaAuthPreferenceV2,
"bot": provider.GenSchemaBot,
"cluster_maintenance_config": tfschema.GenSchemaClusterMaintenanceConfigV1,
"cluster_networking_config": tfschema.GenSchemaClusterNetworkingConfigV2,
"database": tfschema.GenSchemaDatabaseV3,
"trusted_device": devicetrustSchema.GenSchemaDeviceV1,
"github_connector": tfschema.GenSchemaGithubConnectorV3,
"login_rule": loginruleSchema.GenSchemaLoginRule,
"okta_import_rule": tfschema.GenSchemaOktaImportRuleV1,
"oidc_connector": tfschema.GenSchemaOIDCConnectorV3,
"provision_token": tfschema.GenSchemaProvisionTokenV2,
"role": tfschema.GenSchemaRoleV6,
"saml_connector": tfschema.GenSchemaSAMLConnectorV2,
"session_recording_config": tfschema.GenSchemaSessionRecordingConfigV2,
"trusted_cluster": tfschema.GenSchemaTrustedClusterV2,
"user": tfschema.GenSchemaUserV2,
"server": tfschema.GenSchemaServerV2,
}
// hiddenFields are fields that are not outputted to the reference doc.
// It supports non-top level fields by adding its prefix. Eg: metadata.namespace
hiddenFields = []string{
"id", // read only field
"kind", // each resource already defines its kind so this is redundant
}
// fieldComments is used to define specific descriptions for the given fields.
// Typical usage is for enums which we don't have comments yet.
fieldComments = map[string]string{
"teleport_auth_preference.spec.require_session_mfa": "RequireMFAType is the type of MFA requirement enforced for this cluster: 0:Off, 1:Session, 2:SessionAndHardwareKey, 3:HardwareKeyTouch",
"teleport_role.spec.options.require_session_mfa": "RequireMFAType is the type of MFA requirement enforced for this role: 0:Off, 1:Session, 2:SessionAndHardwareKey, 3:HardwareKeyTouch",
}
)
func genReferenceDocs() {
sortedNames := make([]string, 0, len(mapResourceSchema))
for k := range mapResourceSchema {
sortedNames = append(sortedNames, k)
}
sort.Strings(sortedNames)
t, err := template.ParseFiles(path.Join("gen", referenceDocsTemplate))
if err != nil {
log.Fatal(err)
}
referenceDocsResource := make([]referenceDocResource, 0, len(mapResourceSchema))
for _, name := range sortedNames {
resourceName := "teleport_" + name
schemaFn := mapResourceSchema[name]
schema, diags := schemaFn(context.Background())
if diags.HasError() {
log.Fatalf("%v", diags)
}
fieldDescBuilder := strings.Builder{}
dumpAttributes(&fieldDescBuilder, 0, resourceName, "", schema.Attributes)
exampleFileName := fmt.Sprintf("example/%s.tf.example", name)
exampleBytes, err := os.ReadFile(exampleFileName)
if err != nil {
log.Fatalf("error loading %q file: %v", exampleFileName, err)
}
referenceDocsResource = append(referenceDocsResource, referenceDocResource{
Name: resourceName,
FieldsDesc: fieldDescBuilder.String(),
Example: string(exampleBytes),
})
}
var b bytes.Buffer
err = t.ExecuteTemplate(&b, referenceDocsTemplate, map[string]any{
"resourceList": sortedNames,
"resourcesDoc": referenceDocsResource,
})
if err != nil {
log.Fatal(err)
}
err = os.WriteFile("reference.mdx", b.Bytes(), 0777)
if err != nil {
log.Fatal(err)
}
}
type referenceDocResource struct {
Name string
FieldsDesc string
Example string
}
func dumpAttributes(fp io.Writer, level int, resourceName string, prefix string, attrs map[string]tfsdk.Attribute) {
sortedAttrKeys := make([]string, 0, len(attrs))
for k := range attrs {
sortedAttrKeys = append(sortedAttrKeys, k)
}
sort.Strings(sortedAttrKeys)
table := tablewriter.NewWriter(fp)
table.SetHeader([]string{"Name", "Type", "Required", "Description"})
table.SetAutoWrapText(false)
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
table.SetAutoFormatHeaders(false)
for _, name := range sortedAttrKeys {
fullFieldPath := resourceName + "." + prefix + name
attr := attrs[name]
if slices.Contains(hiddenFields, prefix+name) {
continue
}
description := attr.Description
if d, found := fieldComments[fullFieldPath]; found {
description = d
}
// Using html.EscapeString also escapes `'`` (into `&#39;`)
// This generates a lint error when running cspell because the word `doesn't` becomes `doesn&#39;t`
// and `doesn` isn't a valid word.
// This lint error happens when running the `Lint (docs)` CI step in the teleport repo.
// The mdx format supports `'"&` (the other chars that html.EscapeString escapes) without escaping.
descriptionMDXEscaped := strings.ReplaceAll(strings.ReplaceAll(description, "<", "&lt;"), ">", "&gt;")
table.Append([]string{name, typ(attr.Type), requiredString(attr.Required), descriptionMDXEscaped})
}
table.Render()
fmt.Fprintln(fp)
for _, name := range sortedAttrKeys {
attr := attrs[name]
if attr.Attributes != nil {
fmt.Fprintf(fp, "%s %s\n", strings.Repeat("#", 3+level), prefix+name)
fmt.Fprintln(fp)
fmt.Fprintln(fp, attr.Description)
fmt.Fprintln(fp)
dumpAttributes(fp, level+1, resourceName, prefix+name+".", attr.Attributes.GetAttributes())
}
}
}
func typ(typ attr.Type) string {
if typ == nil {
return "object"
}
switch typ.String() {
case "types.StringType":
return "string"
case "TimeType(2006-01-02T15:04:05Z07:00)":
return "RFC3339 time"
case "DurationType":
return "duration"
case "types.BoolType":
return "bool"
case "types.MapType[types.StringType]":
return "map of strings"
case "types.ListType[types.StringType]":
return "array of strings"
case "types.MapType[types.ListType[types.StringType]]":
return "map of string arrays"
case "types.Int64Type":
return "number"
default:
return typ.String()
}
}
func requiredString(r bool) string {
if r {
return "*"
}
return " "
}
@@ -0,0 +1,96 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
{{ if not .IsPlainStruct }}
{{- protoImport . }}
{{- end }}
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
{{- if .Namespaced }}
"github.com/gravitational/teleport/api/defaults"
{{- end }}
{{ schemaImport . }}
)
// dataSourceTeleport{{.Name}}Type is the data source metadata type
type dataSourceTeleport{{.Name}}Type struct{}
// dataSourceTeleport{{.Name}} is the resource
type dataSourceTeleport{{.Name}} struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleport{{.Name}}Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return {{.SchemaPackage}}.GenSchema{{.TypeName}}(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleport{{.Name}}Type) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleport{{.Name}}{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport {{.Name}}
func (r dataSourceTeleport{{.Name}}) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
{{- if .ConvertPackagePath}}
diags := req.Config.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
{{- else }}
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
{{- end}}
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}}I, err := r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}id.Value{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
var state types.Object
{{if .IsPlainStruct -}}
{{.VarName}} := {{.VarName}}I
{{else if .ConvertPackagePath -}}
{{.VarName}} := convert.ToProto({{.VarName}}I)
{{else}}
{{.VarName}} := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
{{- end}}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,448 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
{{- if .RandomMetadataName }}
"crypto/rand"
"encoding/hex"
{{- end }}
"fmt"
{{- range $i, $a := .ExtraImports }}
"{{$a}}"
{{- end }}
{{ if .UUIDMetadataName }}
"github.com/google/uuid"
{{- end }}
{{.ProtoPackage}} "{{.ProtoPackagePath}}"
{{ if .ConvertPackagePath -}}
convert "{{.ConvertPackagePath}}"
{{- end}}
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
{{- if .Namespaced }}
"github.com/gravitational/teleport/api/defaults"
{{- end }}
{{ schemaImport . }}
)
// resourceTeleport{{.Name}}Type is the resource metadata type
type resourceTeleport{{.Name}}Type struct{}
// resourceTeleport{{.Name}} is the resource
type resourceTeleport{{.Name}} struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleport{{.Name}}Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return {{.SchemaPackage}}.GenSchema{{.TypeName}}(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleport{{.Name}}Type) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleport{{.Name}}{
p: *(p.(*Provider)),
}, nil
}
// Create creates the {{.Name}}
func (r resourceTeleport{{.Name}}) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}} := &{{.ProtoPackage}}.{{.TypeName}}{}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}FromTerraform(ctx, plan, {{.VarName}})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{if .RandomMetadataName -}}
if {{.VarName}}.Metadata.Name == "" {
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
resp.Diagnostics.AddError("Failed to generate random token", err.Error())
return
}
{{.VarName}}.Metadata.Name = hex.EncodeToString(b)
}
{{end -}}
{{if .UUIDMetadataName -}}
if {{.VarName}}.Metadata.Name == "" {
{{.VarName}}.Metadata.Name = uuid.NewString()
}
{{end -}}
{{if .DefaultVersion -}}
if {{.VarName}}.Version == "" {
{{.VarName}}.Version = "{{.DefaultVersion}}"
}
{{- end}}
{{- if .ConvertPackagePath}}
{{.VarName}}Resource, err := convert.FromProto({{.VarName}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Errorf("Can not convert %T to {{.TypeName}}: %s", {{.VarName}}Resource, err), "{{.Kind}}"))
return
}
{{- else }}
{{.VarName}}Resource := {{.VarName}}
{{end}}
{{- if .ForceSetKind }}
{{.VarName}}Resource.Kind = {{.ForceSetKind}}
{{- end}}
{{- if .HasCheckAndSetDefaults }}
err = {{.VarName}}Resource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting {{.Name}} defaults", trace.Wrap(err), "{{.Kind}}"))
return
}
{{- end}}
id := {{.VarName}}Resource.Metadata.Name
_, err = r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}id{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("{{.Name}} exists in Teleport. Either remove it (tctl rm {{.Kind}}/%v)"+
" or import it to the existing state (terraform import {{.TerraformResourceType}}.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("{{.Name}} exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if eq .UpsertMethodArity 2}}_, {{end}}err = r.p.Client.{{.CreateMethod}}(ctx, {{.VarName}}Resource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{- if .IsPlainStruct }}
var {{.VarName}}I *{{.ProtoPackage}}.{{.Name}}
{{- else }}
{{if .ConvertPackagePath -}}
var {{.VarName}}I = {{.VarName}}Resource
{{- else }}
// Not really an inferface, just using the same name for easier templating.
var {{.VarName}}I {{.ProtoPackage}}.{{ if ne .IfaceName ""}}{{.IfaceName}}{{else}}{{.Name}}{{end}}
{{- end}}
{{- end }}
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
{{.VarName}}I, err = r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}id{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(bErr), "{{.Kind}}"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading {{.Name}} (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "{{.Kind}}")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if or .IsPlainStruct .ConvertPackagePath -}}
{{.VarName}}Resource = {{.VarName}}I
{{else -}}
{{.VarName}}Resource, ok := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Errorf("Can not convert %T to {{.TypeName}}", {{.VarName}}I), "{{.Kind}}"))
return
}
{{- end}}
{{- if .ConvertPackagePath}}
{{.VarName}} = convert.ToProto({{.VarName}}Resource)
{{else}}
{{.VarName}} = {{.VarName}}Resource
{{- end }}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: {{.ID}}}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
{{- if .ConvertPackagePath}}
diags = req.State.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
{{- else }}
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
{{- end}}
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}}I, err := r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}id.Value{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if .IsPlainStruct -}}
{{.VarName}} := {{.VarName}}I
{{else if .ConvertPackagePath -}}
{{.VarName}} := convert.ToProto({{.VarName}}I)
{{ else }}
{{.VarName}} := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
{{end -}}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}} := &{{.ProtoPackage}}.{{.TypeName}}{}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}FromTerraform(ctx, plan, {{.VarName}})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{- if .ConvertPackagePath}}
{{.VarName}}Resource, err := convert.FromProto({{.VarName}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Errorf("Can not convert %T to {{.TypeName}}: %s", {{.VarName}}Resource, err), "{{.Kind}}"))
return
}
{{- else }}
{{.VarName}}Resource := {{.VarName}}
{{end}}
{{if .HasCheckAndSetDefaults -}}
if err := {{.VarName}}Resource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating {{.Name}}", err, "{{.Kind}}"))
return
}
{{- end}}
name := {{.VarName}}Resource.Metadata.Name
{{.VarName}}Before, err := r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}name{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", err, "{{.Kind}}"))
return
}
{{- $VarName := .VarName }}
{{- range $field := .PropagatedFields }}
{{ $VarName }}Resource.{{ $field }} = {{ $VarName }}Before.{{ $field }}
{{- end }}
{{if eq .UpsertMethodArity 2}}_, {{end}}err = r.p.Client.{{.UpdateMethod}}(ctx, {{.VarName}}Resource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating {{.Name}}", err, "{{.Kind}}"))
return
}
{{- if .IsPlainStruct }}
var {{.VarName}}I *{{.ProtoPackage}}.{{.Name}}
{{- else }}
{{if .ConvertPackagePath -}}
var {{.VarName}}I = {{.VarName}}Resource
{{- else }}
// Not really an inferface, just using the same name for easier templating.
var {{.VarName}}I {{.ProtoPackage}}.{{ if ne .IfaceName ""}}{{.IfaceName}}{{else}}{{.Name}}{{end}}
{{- end}}
{{- end }}
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
{{.VarName}}I, err = r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}name{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", err, "{{.Kind}}"))
return
}
if {{.VarName}}Before.GetMetadata().Revision != {{.VarName}}I.GetMetadata().Revision || {{.HasStaticID}} {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading {{.Name}} (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "{{.Kind}}")
return
}
}
{{if or .IsPlainStruct .ConvertPackagePath -}}
{{.VarName}}Resource = {{.VarName}}I
{{else -}}
{{.VarName}}Resource, ok := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Errorf("Can not convert %T to {{.TypeName}}", {{.VarName}}I), "{{.Kind}}"))
return
}
{{- end}}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
{{- if .ConvertPackagePath}}
diags := req.State.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
{{- else }}
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
{{- end}}
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.{{.DeleteMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting {{.TypeName}}", trace.Wrap(err), "{{.Kind}}"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports {{.Name}} state
func (r resourceTeleport{{.Name}}) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
{{.VarName}}, err := r.p.Client.{{.GetMethod}}(ctx, {{if .Namespaced}}defaults.Namespace, {{end}}req.ID{{if ne .WithSecrets ""}}, {{.WithSecrets}}{{end}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if .IsPlainStruct -}}
{{.VarName}}Resource := {{.VarName}}
{{else if .ConvertPackagePath -}}
{{.VarName}}Resource := convert.ToProto({{.VarName}})
{{else}}
{{.VarName}}Resource := {{.VarName}}.(*{{.ProtoPackage}}.{{.TypeName}})
{{- end}}
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}Resource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{- if or .IsPlainStruct .ConvertPackagePath}}
id := {{.VarName}}.Metadata.Name
{{- else }}
id := {{.VarName}}Resource.GetName()
{{- end}}
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,118 @@
---
title: Terraform provider resources
description: Terraform provider resources reference
---
{/* Content generated by teleport-plugins/terraform/gen/main.go DO NOT EDIT */}
Supported resources:
{{range $_, $resource := .resourceList}}
- [teleport_{{$resource}}](#teleport_{{$resource}})
{{- end}}
## Provider configuration
Ensure your Terraform version is v(=terraform.version=) or higher.
Add the following configuration section to your `terraform` configuration block:
```
terraform {
required_providers {
teleport = {
version = "~> (=teleport.major_version=).0"
source = "terraform.releases.teleport.dev/gravitational/teleport"
}
}
}
```
The provider supports the following options:
| Name | Type | Description | Environment Variable |
| ---------------------- | ------ | ------------------------------------------------------------------------------ | ---------------------------------- |
| `addr` | string | Teleport auth or proxy address in "host:port" format. | `TF_TELEPORT_ADDR` |
| `cert_path` | string | Path to Teleport certificate file. | `TF_TELEPORT_CERT` |
| `cert_base64` | string | Teleport certificate as base64. | `TF_TELEPORT_CERT_BASE64` |
| `identity_file_path` | string | Path to Teleport identity file. | `TF_TELEPORT_IDENTITY_FILE_PATH` |
| `identity_file_base64` | string | Teleport identity file as base64. | `TF_TELEPORT_IDENTITY_FILE_BASE64` |
| `key_path` | string | Path to Teleport key file. | `TF_TELEPORT_KEY` |
| `key_base64` | string | Teleport key as base64. | `TF_TELEPORT_KEY_BASE64` |
| `profile_dir` | string | Teleport profile path. | `TF_TELEPORT_PROFILE_PATH` |
| `profile_name` | string | Teleport profile name. | `TF_TELEPORT_PROFILE_NAME` |
| `root_ca_path` | string | Path to Teleport CA file. | `TF_TELEPORT_ROOT_CA` |
| `root_ca_base64` | string | Teleport CA as base64. | `TF_TELEPORT_ROOT_CA_BASE64` |
| `retry_base_duration` | string | Base duration between retries. [Format](https://pkg.go.dev/time#ParseDuration) | `TF_TELEPORT_RETRY_BASE_DURATION` |
| `retry_cap_duration` | string | Max duration between retries. [Format](https://pkg.go.dev/time#ParseDuration) | `TF_TELEPORT_RETRY_CAP_DURATION` |
| `retry_max_tries` | string | Max number of retries. | `TF_TELEPORT_RETRY_MAX_TRIES` |
You need to specify at least one of:
- `cert_path`, `key_path`,`root_ca_path` and `addr` to connect using key files.
- `cert_base64`, `key_base64`,`root_ca_base64` and `addr` to connect using a base64-encoded key.
- `identity_file_path` or `identity_file_base64` and `addr` to connect using an identity file.
- `profile_name`, `profile_dir` (both can be empty) and `addr` to connect using current profile from `~/.tsh`
The `retry_*` values are used to retry the API calls to Teleport when the cache is stale.
If more than one are provided, they will be tried in the order above until one succeeds.
Example:
```
provider "teleport" {
addr = "localhost:3025"
cert_path = "tf.crt"
key_path = "tf.key"
root_ca_path = "tf.ca"
}
```
## Provider resource versioning
Since Teleport 15, you must set the version on each resource, and version cannot
be changed in-place. Terraform will delete the resource and create a new one if
a version change is required.
This is not enforced on previous Teleport provider versions, but we recommend doing
so. When the version is not specified, Terraform will pick the latest one by default.
However, version upgrades don't re-apply the resource defaults. This could lead
to different results if you create a new resource or upgrade an existing one.
To mitigate this, you should explicitly set the resource version.
<Admonition type="warning">
Upgrading the Terraform Provider to a new version with `teleport_role`
resources without a specified version can change the role behavior and access
rules. You must set the role version before upgrading to ensure the role
access rules don't change.
The default role version is the highest supported:
- v12 default role version is `v5`
- v13 default role version is `v6`
- v14 default role version is `v7`
For example, before upgrading from v12 to v13, edit every unversioned role
to pin the `v5` version:
```hcl
resource "teleport_role" "test" {
version = "v5"
metadata = {
name = "my-role"
}
// ...
}
```
</Admonition>
{{range $_, $resource := .resourcesDoc}}
## {{$resource.Name}}
{{$resource.FieldsDesc -}}
Example:
```
{{$resource.Example}}
```
{{end}}
@@ -0,0 +1,79 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
{{ if not .IsPlainStruct }}
{{- protoImport . }}
{{- end }}
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
{{ schemaImport . }}
)
// dataSourceTeleport{{.Name}}Type is the data source metadata type
type dataSourceTeleport{{.Name}}Type struct{}
// dataSourceTeleport{{.Name}} is the resource
type dataSourceTeleport{{.Name}} struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleport{{.Name}}Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return {{.SchemaPackage}}.GenSchema{{.TypeName}}(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleport{{.Name}}Type) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleport{{.Name}}{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport {{.Name}}
func (r dataSourceTeleport{{.Name}}) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
{{.VarName}}I, err := r.p.Client.{{.GetMethod}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
var state types.Object
{{if .IsPlainStruct -}}
{{.VarName}} := {{.VarName}}I
{{else -}}
{{.VarName}} := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
{{end -}}
diags := {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,336 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
{{- if .WithNonce}}
"math"
{{- end}}
{{.ProtoPackage}} "{{.ProtoPackagePath}}"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
{{ schemaImport . }}
)
// resourceTeleport{{.Name}}Type is the resource metadata type
type resourceTeleport{{.Name}}Type struct{}
// resourceTeleport{{.Name}} is the resource
type resourceTeleport{{.Name}} struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleport{{.Name}}Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return {{.SchemaPackage}}.GenSchema{{.TypeName}}(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleport{{.Name}}Type) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleport{{.Name}}{
p: *(p.(*Provider)),
}, nil
}
// Create creates the {{.Name}}
func (r resourceTeleport{{.Name}}) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}} := &{{.ProtoPackage}}.{{.TypeName}}{}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}FromTerraform(ctx, plan, {{.VarName}})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := {{.VarName}}.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting {{.Name}} defaults", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if .DefaultVersion -}}
if {{.VarName}}.Version == "" {
{{.VarName}}.Version = "{{.DefaultVersion}}"
}
{{- end}}
{{.VarName}}Before, err := r.p.Client.Get{{.Name}}(ctx)
if err != nil && !trace.IsNotFound(err) {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{- if .GetCanReturnNil }}
if {{.VarName}}Before == nil {
{{.VarName}}Before = &{{.ProtoPackage}}.{{.TypeName}}{}
}
{{- end}}
{{- if .WithNonce}}
{{.VarName}} = {{.VarName}}.WithNonce(math.MaxUint64).(*{{.ProtoPackage}}.{{.TypeName}})
{{- end}}
err = r.p.Client.{{.CreateMethod}}(ctx, {{.VarName}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if .IsPlainStruct -}}
// Not really an inferface, just using the same name for easier templating.
var {{.VarName}}I *{{.ProtoPackage}}.{{.Name}}
{{else -}}
var {{.VarName}}I {{.ProtoPackage}}.{{ if ne .IfaceName ""}}{{.IfaceName}}{{else}}{{.Name}}{{end}}
{{- end}}
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
{{.VarName}}I, err = r.p.Client.{{.GetMethod}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
if {{.VarName}}Before.GetMetadata().Revision != {{.VarName}}I.GetMetadata().Revision || {{.HasStaticID}} {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(bErr), "{{.Kind}}"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading {{.Name}} (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "{{.Kind}}")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{if .IsPlainStruct -}}
{{.VarName}} = {{.VarName}}I
{{else -}}
{{.VarName}}, ok := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
if !ok {
resp.Diagnostics.Append(
diagFromWrappedErr("Error reading {{.Name}}", trace.Errorf("Can not convert %T to {{.TypeName}}", {{.VarName}}I), "{{.Kind}}"),
)
return
}
{{- end}}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: {{.ID}}}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}}I, err := r.p.Client.Get{{.Name}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{.VarName}} := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
{{.VarName}} := &{{.ProtoPackage}}.{{.TypeName}}{}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}FromTerraform(ctx, plan, {{.VarName}})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := {{.VarName}}.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{.VarName}}Before, err := r.p.Client.Get{{.Name}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{- $VarName := .VarName }}
{{- range $field := .PropagatedFields }}
{{ $VarName }}.{{ $field }} = {{ $VarName }}Before.{{ $field }}
{{- end }}
{{- if .WithNonce}}
{{.VarName}} = {{.VarName}}.WithNonce(math.MaxUint64).(*{{.ProtoPackage}}.{{.TypeName}})
{{- end}}
err = r.p.Client.{{.UpdateMethod}}(ctx, {{.VarName}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
var {{.VarName}}I {{.ProtoPackage}}.{{ if ne .IfaceName ""}}{{.IfaceName}}{{else}}{{.Name}}{{end}}
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
{{.VarName}}I, err = r.p.Client.{{.GetMethod}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
if {{.VarName}}Before.GetMetadata().Revision != {{.VarName}}I.GetMetadata().Revision || {{.HasStaticID}} {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(bErr), "{{.Kind}}"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading {{.Name}} (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "{{.Kind}}")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{.VarName}} = {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport {{.Name}}
func (r resourceTeleport{{.Name}}) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
err := r.p.Client.{{.DeleteMethod}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports {{.Name}} state
func (r resourceTeleport{{.Name}}) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
{{.VarName}}I, err := r.p.Client.Get{{.Name}}(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating {{.Name}}", trace.Wrap(err), "{{.Kind}}"))
return
}
{{.VarName}} := {{.VarName}}I.(*{{.ProtoPackage}}.{{.TypeName}})
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = {{.SchemaPackage}}.Copy{{.TypeName}}ToTerraform(ctx, {{.VarName}}, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
state.Attrs["id"] = types.String{Value: {{.VarName}}.Metadata.Name}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+354
View File
@@ -0,0 +1,354 @@
module github.com/gravitational/teleport/integrations/terraform
go 1.22
toolchain go1.22.2
require (
github.com/gogo/protobuf v1.3.2
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/gravitational/teleport v0.0.0 // replaced
github.com/gravitational/teleport/api v0.0.0 // replaced
github.com/gravitational/trace v1.4.0
github.com/hashicorp/terraform-plugin-framework v0.10.0
github.com/hashicorp/terraform-plugin-go v0.12.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1
github.com/jonboulle/clockwork v0.4.0
github.com/olekukonko/tablewriter v0.0.5
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.33.0
)
require (
cloud.google.com/go/compute v1.25.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/container v1.35.0 // indirect
cloud.google.com/go/iam v1.1.7 // indirect
cloud.google.com/go/kms v1.15.8 // indirect
connectrpc.com/connect v1.16.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mysql/armmysql v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mysql/armmysqlflexibleservers v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresql v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresqlflexibleservers v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/redis/armredis/v2 v2.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/redisenterprise/armredisenterprise v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
github.com/agext/levenshtein v1.2.2 // indirect
github.com/alecthomas/kingpin/v2 v2.4.0 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/apparentlymart/go-textseg v1.0.0 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.51.16 // indirect
github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/service/athena v1.40.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.156.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ecs v1.41.7 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.42.1 // indirect
github.com/aws/aws-sdk-go-v2/service/glue v1.78.0 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.31.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.76.1 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/beevik/etree v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/containerd/containerd v1.7.12 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
github.com/crewjam/httperr v0.2.0 // indirect
github.com/crewjam/saml v0.4.14 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/di-wu/parser v0.3.0 // indirect
github.com/di-wu/xsd-datetime v1.0.0 // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/docker/cli v25.0.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v25.0.5+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.1 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/elimity-com/scim v0.0.0-20240320110924-172bf2aee9c8 // indirect
github.com/emicklei/go-restful/v3 v3.11.3 // indirect
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/flynn/hid v0.0.0-20190502022136-f1b9b6cc019a // indirect
github.com/flynn/u2f v0.0.0-20180613185708-15554eb68e5d // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/swag v0.22.9 // indirect
github.com/go-piv/piv-go v1.11.0 // indirect
github.com/go-webauthn/webauthn v0.10.2 // indirect
github.com/go-webauthn/x v0.1.9 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/certificate-transparency-go v1.1.7 // indirect
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/google/go-attestation v0.5.1 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/go-tpm-tools v0.4.4 // indirect
github.com/google/go-tspi v0.3.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/gosuri/uitable v0.0.4 // indirect
github.com/gravitational/license v0.0.0-20240313232707-8312e719d624 // indirect
github.com/gravitational/oxy v0.0.0-20231219172753-f855322f2a6c // indirect
github.com/gravitational/roundtrip v1.0.2 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
github.com/hashicorp/go-hclog v1.2.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hc-install v0.3.1 // indirect
github.com/hashicorp/hcl/v2 v2.3.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.15.0 // indirect
github.com/hashicorp/terraform-json v0.13.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.6.0 // indirect
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c // indirect
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/keys-pub/go-libfido2 v1.5.3-0.20220306005615-8ab03fb1ec27 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailgun/holster/v3 v3.16.2 // indirect
github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect
github.com/mailgun/timetools v0.0.0-20170619190023-f3a7b8ffff47 // indirect
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/okta/okta-sdk-golang/v2 v2.20.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 // indirect
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.6 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/cachecontrol v0.1.0 // indirect
github.com/pquerna/otp v1.4.0 // indirect
github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.51.1 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rubenv/sql-migrate v1.5.2 // indirect
github.com/russellhaering/gosaml2 v0.9.1 // indirect
github.com/russellhaering/goxmldsig v1.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sashabaranov/go-openai v1.20.5 // indirect
github.com/schollz/progressbar/v3 v3.14.2 // indirect
github.com/scim2/filter-parser/v2 v2.2.0 // indirect
github.com/sethvargo/go-diceware v0.3.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sijms/go-ora/v2 v2.8.10 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/tiktoken-go/tokenizer v0.1.0 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
github.com/vmihailenco/tagparser v0.1.1 // indirect
github.com/vulcand/predicate v1.2.0 // indirect
github.com/weppos/publicsuffix-go v0.30.1-0.20230620154423-38c92ad2d5c6 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/zclconf/go-cty v1.9.1 // indirect
github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect
github.com/zmap/zlint/v3 v3.5.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 // indirect
go.opentelemetry.io/otel/metric v1.25.0 // indirect
go.opentelemetry.io/otel/sdk v1.25.0 // indirect
go.opentelemetry.io/otel/trace v1.25.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/oauth2 v0.19.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.19.0 // indirect
google.golang.org/api v0.172.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240325164216-beb30f47624b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240325164216-beb30f47624b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
helm.sh/helm/v3 v3.14.3 // indirect
k8s.io/api v0.29.3 // indirect
k8s.io/apiextensions-apiserver v0.29.3 // indirect
k8s.io/apimachinery v0.29.3 // indirect
k8s.io/apiserver v0.29.3 // indirect
k8s.io/cli-runtime v0.29.3 // indirect
k8s.io/client-go v0.29.3 // indirect
k8s.io/component-base v0.29.3 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/kube-openapi v0.0.0-20240224005224-582cce78233b // indirect
k8s.io/kubectl v0.29.3 // indirect
k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect
oras.land/oras-go v1.2.5 // indirect
sigs.k8s.io/controller-runtime v0.17.2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect
)
replace (
github.com/alecthomas/kingpin/v2 => github.com/gravitational/kingpin/v2 v2.1.11-0.20230515143221-4ec6b70ecd33
github.com/coreos/go-oidc => github.com/gravitational/go-oidc v0.1.1
github.com/gogo/protobuf => github.com/gravitational/protobuf v1.3.2-0.20201123192827-2b9fcfaffcbf
github.com/gravitational/teleport => ../../
github.com/gravitational/teleport/api => ../../api
github.com/julienschmidt/httprouter => github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5
github.com/microsoft/go-mssqldb => github.com/gravitational/go-mssqldb v0.11.1-0.20230331180905-0f76f1751cd3
github.com/vulcand/predicate => github.com/gravitational/predicate v1.3.1
)
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
VERSION?=15.1.10
OS ?= $(shell go env GOOS)
ARCH ?= $(shell go env GOARCH)
TERRAFORM_ARCH=$(OS)_$(ARCH)
PROVIDER_PATH = ~/.terraform.d/plugins/terraform.releases.teleport.dev/gravitational/teleport/$(VERSION)/$(TERRAFORM_ARCH)/
.PHONY: install
install: build
mkdir -p $(PROVIDER_PATH)
mv $(BUILDDIR)/terraform-provider-teleport $(PROVIDER_PATH)
+34
View File
@@ -0,0 +1,34 @@
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/gravitational/teleport/integrations/terraform/provider"
)
func main() {
err := providerserver.Serve(context.Background(), provider.New, providerserver.ServeOpts{
Address: "terraform.releases.teleport.dev/gravitational/teleport",
})
if err != nil {
log.Fatal(err)
}
}
@@ -0,0 +1,78 @@
---
target_package_name: "v1"
default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
duration_custom_type: Duration
use_state_for_unknown_by_default: true
# Top-level type names to export
types:
- "AccessList"
# These import paths were not being automatically picked up by
# protoc-gen-terraform without these overrides
import_path_overrides:
"types": "github.com/gravitational/teleport/api/types"
"wrappers": "github.com/gravitational/teleport/api/types/wrappers"
"durationpb": "google.golang.org/protobuf/types/known/durationpb"
"timestamppb": "google.golang.org/protobuf/types/known/timestamppb"
"v1": "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
"v11": "github.com/gravitational/teleport/api/gen/proto/go/teleport/trait/v1"
# id field is required for integration tests. It is not used by provider.
# We have to add it manually (might be removed in the future versions).
injected_fields:
AccessList:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
# These fields will be excluded
exclude_fields:
# Metadata (we id resources by name on our side)
- "AccessList.header.metadata.id"
# Read only field
- "AccessList.spec.owners.ineligible_status"
- "AccessList.status"
# These fields will be marked as Computed: true
computed_fields:
# Metadata
- "AccessList.header.metadata.namespace"
- "AccessList.spec.audit.next_audit_date"
# These fields will be marked as Required: true
required_fields:
- "Metadata.name"
- "AccessList.header.version"
- "AccessList.spec.owners"
- "AccessList.spec.grants"
- "AccessList.spec.audit"
- "AccessList.spec.audit.recurrence"
- "AccessList.spec.audit.recurrence.frequency"
plan_modifiers:
# Force to recreate resource if it's name changes
Metadata.name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
# This must be defined for the generator to be happy, but in reality all time
# fields are overridden (because the protobuf timestamps contain locks and the
# linter gets mad if we use raw structs instead of pointers).
time_type:
type: "PlaceholderType"
duration_type:
type: "PlaceholderType"
validators:
# Expires must be in the future
Metadata.expires:
- github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture()
custom_types:
"AccessList.header.metadata.expires": Timestamp
"AccessList.spec.audit.next_audit_date": Timestamp
"AccessList.spec.audit.frequency": Duration
"AccessList.spec.audit.notifications.start": Duration
@@ -0,0 +1,70 @@
---
target_package_name: "v1"
default_package_name: "github.com/gravitational/teleport/api/types"
use_state_for_unknown_by_default: true
# Top-level type names to export
types:
- "DeviceV1"
# These import paths were not being automatically picked up by
# protoc-gen-terraform without these overrides
import_path_overrides:
"types": "github.com/gravitational/teleport/api/types"
"wrappers": "github.com/gravitational/teleport/api/types/wrappers"
injected_fields:
DeviceV1:
# id field is required for integration tests. It is also used by this provider
# to hold Metadata.name value returned by Teleport.
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
# These fields will be marked as Computed: true
computed_fields:
# Metadata
- "DeviceV1.Metadata"
- "DeviceV1.Kind"
# DeviceV1
- "DeviceV1.spec.enroll_status"
# These fields will be marked as Required: true
required_fields:
- "DeviceV1.spec.asset_tag"
- "DeviceV1.spec.os_type"
- "DeviceV1.Version"
exclude_fields:
# Below fields are either managed or not used on Teleport side
- "DeviceV1.SubKind"
- "DeviceV1.Metadata.ID"
- "DeviceV1.Metadata.Namespace"
- "DeviceV1.Metadata.Description"
- "DeviceV1.Metadata.Expires"
- "DeviceV1.spec.create_time"
- "DeviceV1.spec.update_time"
- "DeviceV1.spec.credential"
- "DeviceV1.spec.collected_data"
- "DeviceV1.spec.profile"
plan_modifiers:
# Force to recreate resource if asset tag changes
"DeviceV1.spec.asset_tag":
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
time_type:
type: "github.com/gravitational/teleport/integrations/terraform/tfschema.TimeType"
value_type: "github.com/gravitational/teleport/integrations/terraform/tfschema.TimeValue"
cast_to_type: "time.Time"
cast_from_type: "time.Time"
type_constructor: "github.com/gravitational/teleport/integrations/terraform/tfschema.UseRFC3339Time()"
@@ -0,0 +1,65 @@
---
target_package_name: "v1"
default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
duration_custom_type: Duration
use_state_for_unknown_by_default: true
# Top-level type names to export
types:
- "LoginRule"
# These import paths were not being automatically picked up by
# protoc-gen-terraform without these overrides
import_path_overrides:
"types": "github.com/gravitational/teleport/api/types"
"wrappers": "github.com/gravitational/teleport/api/types/wrappers"
# id field is required for integration tests. It is not used by provider.
# We have to add it manually (might be removed in the future versions).
injected_fields:
LoginRule:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
# These fields will be excluded
exclude_fields:
# Metadata (we id resources by name on our side)
- "Metadata.ID"
# These fields will be marked as Computed: true
computed_fields:
# Metadata
- "Metadata.Namespace"
# These fields will be marked as Required: true
required_fields:
# LoginRule
- "Metadata.Name"
- "LoginRule.version"
- "LoginRule.priority"
plan_modifiers:
# Force to recreate resource if it's name changes
Metadata.Name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
validators:
Metadata.Expires:
- github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture()
LoginRule:
- github_com_gravitational_teleport_integrations_terraform_tfschema.UseAnyOfValidator("traits_map", "traits_expression")
LoginRule.TraitsExpression:
- github_com_gravitational_teleport_integrations_terraform_tfschema.UseAnyOfValidator("traits_map", "traits_expression")
TraitsExpression:
- github_com_gravitational_teleport_integrations_terraform_tfschema.UseAnyOfValidator("traits_map", "traits_expression")
time_type:
type: "github.com/gravitational/teleport/integrations/terraform/tfschema.TimeType"
value_type: "github.com/gravitational/teleport/integrations/terraform/tfschema.TimeValue"
cast_to_type: "time.Time"
cast_from_type: "time.Time"
type_constructor: "github.com/gravitational/teleport/integrations/terraform/tfschema.UseRFC3339Time()"
@@ -0,0 +1,434 @@
---
target_package_name: "tfschema"
default_package_name: "github.com/gravitational/teleport/api/types"
duration_custom_type: Duration
use_state_for_unknown_by_default: true
# Top-level type names to export
types:
- "AppV3"
- "AuthPreferenceV2"
- "ClusterMaintenanceConfigV1"
- "ClusterNetworkingConfigV2"
- "DatabaseV3"
- "GithubConnectorV3"
- "OIDCConnectorV3"
- "OktaImportRuleV1"
- "ProvisionTokenV2"
- "RoleV6"
- "SAMLConnectorV2"
- "ServerV2"
- "SessionRecordingConfigV2"
- "TrustedClusterV2"
- "UserV2"
# id field is required for integration tests. It is not used by provider.
# We have to add it manually (might be removed in the future versions).
injected_fields:
AppV3:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
AuthPreferenceV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
ClusterMaintenanceConfigV1:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
ClusterNetworkingConfigV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
DatabaseV3:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
GithubConnectorV3:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
OIDCConnectorV3:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
OktaImportRuleV1:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
ProvisionTokenV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
RoleV6:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
SAMLConnectorV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
ServerV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
SessionRecordingConfigV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
TrustedClusterV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
UserV2:
-
name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
# These fields will be excluded
exclude_fields:
# Metadata (we id resources by name on our side)
- "Metadata.ID"
# AuthPreference
- "AuthPreferenceV2.Metadata.Name" # It's a singleton resource
# ClusterMaintenanceConfig
- "ClusterMaintenanceConfigV1.Metadata.Name" # It's a singleton resource
# NetworkingConfig
- "ClusterNetworkingConfigV2.Metadata.Name" # It's a singleton resource
# Status
- "DatabaseV3.Status"
# Role
- "RoleV6.Spec.Allow.Namespaces" # These fields are not settable via API
- "RoleV6.Spec.Deny.Namespaces"
# Server
- "ServerSpecV2.CmdLabels"
# SessionRecordingConfig
- "SessionRecordingConfigV2.Metadata.Name" # It's a singleton resource
# User
- "UserSpecV2.LocalAuth" # We do not need to set user auth data
- "UserSpecV2.Expires" # Those fields are Teleport side meta, we do not need to change them via Terraform
- "UserSpecV2.CreatedBy"
- "UserSpecV2.Status"
name_overrides:
# These fields will be marked as Computed: true
computed_fields:
# Metadata
- "Metadata.Namespace"
# App
- "AppV3.Metadata.Labels"
- "AppV3.Kind"
# Auth preference
- "AuthPreferenceV2.Spec.SecondFactor"
- "AuthPreferenceV2.Spec.Type"
- "AuthPreferenceV2.Spec.LockingMode"
- "AuthPreferenceV2.Metadata.Namespace"
- "AuthPreferenceV2.Metadata.Labels"
- "AuthPreferenceV2.Kind"
# ClusterMaintenanceConfig
- "ClusterMaintenanceConfigV1.Kind"
# Cluster networking
- "ClusterNetworkingConfigV2.Spec.KeepAliveCountMax"
- "ClusterNetworkingConfigV2.Spec.KeepAliveInterval"
- "ClusterNetworkingConfigV2.Kind"
- "ClusterNetworkingConfigV2.Version"
# Database
- "DatabaseV3.Kind"
# Github connector
- "GithubConnectorV3.Kind"
# Provision token
- "ProvisionTokenV2.Spec.AWSIIDTTL"
- "ProvisionTokenV2.Kind"
- "ProvisionTokenV2.Metadata.Name"
# OIDC connector
- "OIDCConnectorV3.Kind"
# Okta import rule
- "OktaImportRuleV1.Kind"
# Role
- "RoleV6.Spec.Options.MaxSessionTTL"
- "RoleV6.Spec.Options.CertificateFormat"
# KubernetesResources was added in v12
# When not set, the api returns kind:Pod/name:*/namespace:*
# We must include this as computed, otherwise terraform would complain about an unexpected field:
# https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#computed
# Computed is often used to represent values that are not user configurable or can not be known at time of terraform plan or apply,
#------------------------------------
# role_test.go:244: Step 1/8 error: Error running apply: exit status 1
#
# Error: Provider produced inconsistent result after apply
#
# When applying changes to teleport_role.upgrade, provider
# "provider[\"registry.terraform.io/hashicorp/teleport\"]" produced an
# unexpected new value: .spec.allow.kubernetes_resources: was null, but now
# cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"kind":cty.StringVal("pod"),
# "name":cty.StringVal("*"), "namespace":cty.StringVal("*")})}).
#
# This is a bug in the provider, which should be reported in the provider's own
# issue tracker.
#------------------------------------
# The following tests were added to validate the behavior:
# - TestTerraform/TestRoleVersionUpgrade
# - TestTerraform/TestRoleWithKubernetesResources
- "RoleV6.Spec.Allow.KubernetesResources"
- "RoleV6.Spec.Allow.KubernetesResources.Verbs"
- "RoleV6.Spec.Options.BPF"
- "RoleV6.Kind"
# SAML connector
- "SAMLConnectorV2.Spec.Audience"
- "SAMLConnectorV2.Spec.Issuer"
- "SAMLConnectorV2.Spec.ServiceProviderIssuer"
- "SAMLConnectorV2.Spec.SSO"
- "SAMLConnectorV2.Spec.SigningKeyPair"
- "SAMLConnectorV2.Spec.SigningKeyPair.PrivateKey"
- "SAMLConnectorV2.Spec.SigningKeyPair.Cert"
- "SAMLConnectorV2.Spec.EncryprionKeyPair"
- "SAMLConnectorV2.Spec.EncryptionKeyPair.PrivateKey"
- "SAMLConnectorV2.Spec.EncryptionKeyPair.Cert"
- "SAMLConnectorV2.Kind"
# Server
- "ServerV2.Kind"
# Name is not required for servers, this is a special case.
# When a name is not set, an UUID will be generated by Teleport and
# imported back into Terraform.
# Giving unique IDs to servers allows UUID-based dialing (as opposed to
# host-based dialing and IP-based dialing) which is more robust than its
# counterparts as it can point to a specific server if multiple servers
# share the same hostname/ip.
- "ServerV2.Metadata.Name"
# Metadata must be marked computed as well, because we ccan potentially compute Metadata.Name.
# If there's no metadata and the attribute is not marked as comnputed, it will
# keep its values.Null = true field, which means its content won't be imported
# back into the state.
- "ServerV2.Metadata"
# Session recording
- "SessionRecordingConfigV2.Spec.Mode"
- "SessionRecordingConfigV2.Kind"
# Trusted cluster
- "TrustedClusterV2.Kind"
# User
- "UserV2.Kind"
# These fields will be marked as Required: true
required_fields:
# App
- "AppV3.Metadata.Name"
- "AppV3.Version"
# Auth preference
- "AuthPreferenceV2.Spec"
- "AuthPreferenceV2.Metadata.Name"
# Database
- "DatabaseV3.Spec.Protocol"
- "DatabaseV3.Spec.URI"
- "DatabaseV3.Metadata.Name"
- "DatabaseV3.Version"
# Github connector
- "GithubConnectorV3.Spec"
- "GithubConnectorV3.Spec.ClientID"
- "GithubConnectorV3.Spec.ClientSecret"
- "GithubConnectorV3.Metadata.Name"
- "GithubConnectorV3.Version"
# OIDC connector
- "OIDCConnectorV3.Spec"
- "OIDCConnectorV3.Metadata.Name"
- "OIDCConnectorV3.Version"
# Okta import rule
- "OktaImportRuleV1.Spec"
- "OktaImportRuleV1.Metadata.Name"
- "OktaImportRuleV1.Version"
# Provision token
- "ProvisionTokenV2.Spec"
- "ProvisionTokenV2.Spec.Options"
- "ProvisionTokenV2.Spec.Roles"
- "ProvisionTokenV2.Version"
# Role
- "RoleV6.Metadata.Name"
- "RoleV6.Version"
# SAML connector
- "SAMLConnectorV2.Spec"
- "SAMLConnectorV2.Spec.AssertionConsumerService"
- "SAMLConnectorV2.Spec.AttributesToRoles"
- "SAMLConnectorV2.Metadata.Name"
- "SAMLConnectorV2.Version"
# Server
- "ServerV2.Version"
- "ServerV2.SubKind"
# Trusted cluster
- "TrustedClusterV2.Metadata.Name"
- "TrustedClusterV2.Version"
- "TrustedClusterV2.Spec"
# User
- "UserV2.Metadata.Name"
- "UserV2.Version"
- "SessionRecordingConfigV2.Version"
- "ClusterMaintenanceConfigV1.Version"
- "AuthPreferenceV2.Version"
# These fields must be marked as sensitive
sensitive_fields:
- "ProvisionTokenV2.Metadata.Name"
- "SAMLConnectorV2.Spec.Cert"
- "SAMLConnectorV2.Spec.SigningKeyPair.PrivateKey"
- "SAMLConnectorV2.Spec.EncryptionKeyPair.PrivateKey"
- "SAMLConnectorV2.Spec.EntityDescriptor"
- "GithubConnectorV3.Spec.ClientSecret"
- "OIDCConnectorV3.Spec.ClientSecret"
- "OIDCConnectorV3.Spec.GoogleServiceAccount"
- "TrustedClusterV2.Spec.Token"
# These suffixes for custom methods called when field has custom_type flag. By default they might be weird.
suffixes:
"BoolOption": "BoolOption" # This is listed here for convenience. Just to have all custom method names in a single place.
"Labels": "Labels"
"github.com/gravitational/teleport/api/types/wrappers.Traits": "Traits"
"github.com/gravitational/teleport/api/types/wrappers.Strings": "Strings"
plan_modifiers:
# Force to recreate resource if it's name changes
Metadata.Name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
ProvisionTokenV2.Metadata.Name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
ServerV2.Metadata.Name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"
validators:
# Expires must be in the future
Metadata.Expires:
- MustTimeBeInFuture()
AppV3.Version:
- UseVersionBetween(3,3)
AuthPreferenceV2.Version:
- UseVersionBetween(2,2)
AuthPreferenceV2.Metadata.Labels:
- UseMapKeysPresentValidator("teleport.dev/origin")
ClusterNetworkingConfigV2.Version:
- UseVersionBetween(2,2)
ClusterNetworkingConfigV2.Metadata.Labels:
- UseMapKeysPresentValidator("teleport.dev/origin")
DatabaseV3.Version:
- UseVersionBetween(3,3)
DatabaseV3.Metadata.Labels:
- UseMapKeysPresentValidator("teleport.dev/origin")
GithubConnectorV3.Version:
- UseVersionBetween(3,3)
OIDCConnectorV3.Version:
- UseVersionBetween(3,3)
OktaImportRuleV1.Version:
- UseVersionBetween(1,1)
ProvisionTokenV2.Version:
- UseVersionBetween(2,2)
RoleV6.Version:
- UseVersionBetween(3,7)
SAMLConnectorV2.Version:
- UseVersionBetween(2,2)
SAMLConnectorV2.Spec:
- UseAnyOfValidator("entity_descriptor", "entity_descriptor_url")
ServerV2.Version:
- UseVersionBetween(2,2)
ServerV2.SubKind:
- UseValueIn("openssh", "openssh-ec2-ice")
SessionRecordingConfigV2.Version:
- UseVersionBetween(2,2)
SessionRecordingConfigV2.Metadata.Labels:
- UseMapKeysPresentValidator("teleport.dev/origin")
UserV2.Version:
- UseVersionBetween(2,2)
ClusterMaintenanceConfigV1.Version:
- UseVersionBetween(1,1)
time_type:
type: "TimeType"
value_type: "TimeValue"
cast_to_type: "time.Time"
cast_from_type: "time.Time"
type_constructor: UseRFC3339Time()
duration_type:
type: "DurationType"
value_type: "DurationValue"
cast_to_type: "time.Duration"
cast_from_type: "time.Duration"
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
convert "github.com/gravitational/teleport/api/types/accesslist/convert/v1"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/accesslist/v1"
)
// dataSourceTeleportAccessListType is the data source metadata type
type dataSourceTeleportAccessListType struct{}
// dataSourceTeleportAccessList is the resource
type dataSourceTeleportAccessList struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportAccessListType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaAccessList(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportAccessListType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportAccessList{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport AccessList
func (r dataSourceTeleportAccessList) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessListI, err := r.p.Client.AccessListClient().GetAccessList(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
var state types.Object
accessList := convert.ToProto(accessListI)
diags = schemav1.CopyAccessListToTerraform(ctx, accessList, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportAppType is the data source metadata type
type dataSourceTeleportAppType struct{}
// dataSourceTeleportApp is the resource
type dataSourceTeleportApp struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportAppType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaAppV3(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportAppType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportApp{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport App
func (r dataSourceTeleportApp) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
appI, err := r.p.Client.GetApp(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
var state types.Object
app := appI.(*apitypes.AppV3)
diags = tfschema.CopyAppV3ToTerraform(ctx, app, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,73 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportAuthPreferenceType is the data source metadata type
type dataSourceTeleportAuthPreferenceType struct{}
// dataSourceTeleportAuthPreference is the resource
type dataSourceTeleportAuthPreference struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportAuthPreferenceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaAuthPreferenceV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportAuthPreferenceType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportAuthPreference{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport AuthPreference
func (r dataSourceTeleportAuthPreference) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
authPreferenceI, err := r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
var state types.Object
authPreference := authPreferenceI.(*apitypes.AuthPreferenceV2)
diags := tfschema.CopyAuthPreferenceV2ToTerraform(ctx, authPreference, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,73 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportClusterMaintenanceConfigType is the data source metadata type
type dataSourceTeleportClusterMaintenanceConfigType struct{}
// dataSourceTeleportClusterMaintenanceConfig is the resource
type dataSourceTeleportClusterMaintenanceConfig struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportClusterMaintenanceConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaClusterMaintenanceConfigV1(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportClusterMaintenanceConfigType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportClusterMaintenanceConfig{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport ClusterMaintenanceConfig
func (r dataSourceTeleportClusterMaintenanceConfig) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
clusterMaintenanceConfigI, err := r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
var state types.Object
clusterMaintenanceConfig := clusterMaintenanceConfigI.(*apitypes.ClusterMaintenanceConfigV1)
diags := tfschema.CopyClusterMaintenanceConfigV1ToTerraform(ctx, clusterMaintenanceConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,73 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportClusterNetworkingConfigType is the data source metadata type
type dataSourceTeleportClusterNetworkingConfigType struct{}
// dataSourceTeleportClusterNetworkingConfig is the resource
type dataSourceTeleportClusterNetworkingConfig struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportClusterNetworkingConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaClusterNetworkingConfigV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportClusterNetworkingConfigType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportClusterNetworkingConfig{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport ClusterNetworkingConfig
func (r dataSourceTeleportClusterNetworkingConfig) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
clusterNetworkingConfigI, err := r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
var state types.Object
clusterNetworkingConfig := clusterNetworkingConfigI.(*apitypes.ClusterNetworkingConfigV2)
diags := tfschema.CopyClusterNetworkingConfigV2ToTerraform(ctx, clusterNetworkingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportDatabaseType is the data source metadata type
type dataSourceTeleportDatabaseType struct{}
// dataSourceTeleportDatabase is the resource
type dataSourceTeleportDatabase struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportDatabaseType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaDatabaseV3(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportDatabaseType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportDatabase{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport Database
func (r dataSourceTeleportDatabase) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
databaseI, err := r.p.Client.GetDatabase(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
var state types.Object
database := databaseI.(*apitypes.DatabaseV3)
diags = tfschema.CopyDatabaseV3ToTerraform(ctx, database, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/devicetrust/v1"
)
// dataSourceTeleportDeviceV1Type is the data source metadata type
type dataSourceTeleportDeviceV1Type struct{}
// dataSourceTeleportDeviceV1 is the resource
type dataSourceTeleportDeviceV1 struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportDeviceV1Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaDeviceV1(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportDeviceV1Type) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportDeviceV1{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport DeviceV1
func (r dataSourceTeleportDeviceV1) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedDeviceI, err := r.p.Client.GetDeviceResource(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
var state types.Object
trustedDevice := trustedDeviceI
diags = schemav1.CopyDeviceV1ToTerraform(ctx, trustedDevice, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportGithubConnectorType is the data source metadata type
type dataSourceTeleportGithubConnectorType struct{}
// dataSourceTeleportGithubConnector is the resource
type dataSourceTeleportGithubConnector struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportGithubConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaGithubConnectorV3(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportGithubConnectorType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportGithubConnector{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport GithubConnector
func (r dataSourceTeleportGithubConnector) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnectorI, err := r.p.Client.GetGithubConnector(ctx, id.Value, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
var state types.Object
githubConnector := githubConnectorI.(*apitypes.GithubConnectorV3)
diags = tfschema.CopyGithubConnectorV3ToTerraform(ctx, githubConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/loginrule/v1"
)
// dataSourceTeleportLoginRuleType is the data source metadata type
type dataSourceTeleportLoginRuleType struct{}
// dataSourceTeleportLoginRule is the resource
type dataSourceTeleportLoginRule struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportLoginRuleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaLoginRule(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportLoginRuleType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportLoginRule{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport LoginRule
func (r dataSourceTeleportLoginRule) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRuleI, err := r.p.Client.GetLoginRule(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
var state types.Object
loginRule := loginRuleI
diags = schemav1.CopyLoginRuleToTerraform(ctx, loginRule, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportOIDCConnectorType is the data source metadata type
type dataSourceTeleportOIDCConnectorType struct{}
// dataSourceTeleportOIDCConnector is the resource
type dataSourceTeleportOIDCConnector struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportOIDCConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaOIDCConnectorV3(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportOIDCConnectorType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportOIDCConnector{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport OIDCConnector
func (r dataSourceTeleportOIDCConnector) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnectorI, err := r.p.Client.GetOIDCConnector(ctx, id.Value, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
var state types.Object
oidcConnector := oidcConnectorI.(*apitypes.OIDCConnectorV3)
diags = tfschema.CopyOIDCConnectorV3ToTerraform(ctx, oidcConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportOktaImportRuleType is the data source metadata type
type dataSourceTeleportOktaImportRuleType struct{}
// dataSourceTeleportOktaImportRule is the resource
type dataSourceTeleportOktaImportRule struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportOktaImportRuleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaOktaImportRuleV1(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportOktaImportRuleType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportOktaImportRule{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport OktaImportRule
func (r dataSourceTeleportOktaImportRule) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRuleI, err := r.p.Client.OktaClient().GetOktaImportRule(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
var state types.Object
oktaImportRule := oktaImportRuleI.(*apitypes.OktaImportRuleV1)
diags = tfschema.CopyOktaImportRuleV1ToTerraform(ctx, oktaImportRule, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportProvisionTokenType is the data source metadata type
type dataSourceTeleportProvisionTokenType struct{}
// dataSourceTeleportProvisionToken is the resource
type dataSourceTeleportProvisionToken struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportProvisionTokenType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaProvisionTokenV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportProvisionTokenType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportProvisionToken{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport ProvisionToken
func (r dataSourceTeleportProvisionToken) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
provisionTokenI, err := r.p.Client.GetToken(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
var state types.Object
provisionToken := provisionTokenI.(*apitypes.ProvisionTokenV2)
diags = tfschema.CopyProvisionTokenV2ToTerraform(ctx, provisionToken, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportRoleType is the data source metadata type
type dataSourceTeleportRoleType struct{}
// dataSourceTeleportRole is the resource
type dataSourceTeleportRole struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportRoleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaRoleV6(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportRoleType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportRole{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport Role
func (r dataSourceTeleportRole) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
roleI, err := r.p.Client.GetRole(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
var state types.Object
role := roleI.(*apitypes.RoleV6)
diags = tfschema.CopyRoleV6ToTerraform(ctx, role, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportSAMLConnectorType is the data source metadata type
type dataSourceTeleportSAMLConnectorType struct{}
// dataSourceTeleportSAMLConnector is the resource
type dataSourceTeleportSAMLConnector struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportSAMLConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaSAMLConnectorV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportSAMLConnectorType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportSAMLConnector{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport SAMLConnector
func (r dataSourceTeleportSAMLConnector) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnectorI, err := r.p.Client.GetSAMLConnector(ctx, id.Value, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
var state types.Object
samlConnector := samlConnectorI.(*apitypes.SAMLConnectorV2)
diags = tfschema.CopySAMLConnectorV2ToTerraform(ctx, samlConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,83 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportServerType is the data source metadata type
type dataSourceTeleportServerType struct{}
// dataSourceTeleportServer is the resource
type dataSourceTeleportServer struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportServerType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaServerV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportServerType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportServer{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport Server
func (r dataSourceTeleportServer) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
serverI, err := r.p.Client.GetNode(ctx, defaults.Namespace, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
var state types.Object
server := serverI.(*apitypes.ServerV2)
diags = tfschema.CopyServerV2ToTerraform(ctx, server, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,73 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportSessionRecordingConfigType is the data source metadata type
type dataSourceTeleportSessionRecordingConfigType struct{}
// dataSourceTeleportSessionRecordingConfig is the resource
type dataSourceTeleportSessionRecordingConfig struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportSessionRecordingConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaSessionRecordingConfigV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportSessionRecordingConfigType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportSessionRecordingConfig{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport SessionRecordingConfig
func (r dataSourceTeleportSessionRecordingConfig) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
sessionRecordingConfigI, err := r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
var state types.Object
sessionRecordingConfig := sessionRecordingConfigI.(*apitypes.SessionRecordingConfigV2)
diags := tfschema.CopySessionRecordingConfigV2ToTerraform(ctx, sessionRecordingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportTrustedClusterType is the data source metadata type
type dataSourceTeleportTrustedClusterType struct{}
// dataSourceTeleportTrustedCluster is the resource
type dataSourceTeleportTrustedCluster struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportTrustedClusterType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaTrustedClusterV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportTrustedClusterType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportTrustedCluster{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport TrustedCluster
func (r dataSourceTeleportTrustedCluster) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedClusterI, err := r.p.Client.GetTrustedCluster(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
var state types.Object
trustedCluster := trustedClusterI.(*apitypes.TrustedClusterV2)
diags = tfschema.CopyTrustedClusterV2ToTerraform(ctx, trustedCluster, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,82 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// dataSourceTeleportUserType is the data source metadata type
type dataSourceTeleportUserType struct{}
// dataSourceTeleportUser is the resource
type dataSourceTeleportUser struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportUserType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaUserV2(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportUserType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportUser{
p: *(p.(*Provider)),
}, nil
}
// Read reads teleport User
func (r dataSourceTeleportUser) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) {
var id types.String
diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
userI, err := r.p.Client.GetUser(ctx, id.Value, false)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
var state types.Object
user := userI.(*apitypes.UserV2)
diags = tfschema.CopyUserV2ToTerraform(ctx, user, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+51
View File
@@ -0,0 +1,51 @@
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
log "github.com/sirupsen/logrus"
)
// diagFromWrappedErr wraps error with additional information
func diagFromWrappedErr(summary string, err error, kind string) diag.Diagnostic {
var notFoundErr = "Terraform user has no rights to perform this action. Check that Terraform user role has " +
"['list','create','read','update','delete'] verbs for '" + kind + "' resource."
var accessDeniedErr = "Terraform user is missing on the Teleport side. Check that your auth credentials (certs) " +
"specified in provider configuration belong to existing user and are not expired."
if trace.IsNotFound(err) {
return diagFromErr(summary, trace.WrapWithMessage(err, notFoundErr))
}
if trace.IsAccessDenied(err) {
return diagFromErr(summary, trace.WrapWithMessage(err, accessDeniedErr))
}
return diagFromErr(summary, trace.Wrap(err))
}
// diagFromErr converts error to diag.Diagnostics. If logging level is debug, provides trace.DebugReport instead of short text.
func diagFromErr(summary string, err error) diag.Diagnostic {
if log.GetLevel() >= log.DebugLevel {
return diag.NewErrorDiagnostic(err.Error(), trace.DebugReport(err))
}
return diag.NewErrorDiagnostic(summary, err.Error())
}
+609
View File
@@ -0,0 +1,609 @@
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
)
const (
// minServerVersion is the minimal teleport version the plugin supports.
minServerVersion = "15.0.0-0"
)
type RetryConfig struct {
Base time.Duration
Cap time.Duration
MaxTries int
}
// Provider Teleport Provider
type Provider struct {
configured bool
Client *client.Client
RetryConfig RetryConfig
}
// providerData provider schema struct
type providerData struct {
// Addr Teleport address
Addr types.String `tfsdk:"addr"`
// CertPath path to TLS certificate file
CertPath types.String `tfsdk:"cert_path"`
// CertBase64 base64 encoded TLS certificate file
CertBase64 types.String `tfsdk:"cert_base64"`
// KeyPath path to TLS private key file
KeyPath types.String `tfsdk:"key_path"`
// KeyBase64 base64 encoded TLS private key
KeyBase64 types.String `tfsdk:"key_base64"`
// RootCAPath path to TLS root CA certificate file
RootCaPath types.String `tfsdk:"root_ca_path"`
// RootCaPath base64 encoded root CA certificate
RootCaBase64 types.String `tfsdk:"root_ca_base64"`
// ProfileName Teleport profile name
ProfileName types.String `tfsdk:"profile_name"`
// ProfileDir Teleport profile dir
ProfileDir types.String `tfsdk:"profile_dir"`
// IdentityFilePath path to identity file
IdentityFilePath types.String `tfsdk:"identity_file_path"`
// IdentityFile identity file content
IdentityFile types.String `tfsdk:"identity_file"`
// IdentityFile identity file content encoded in base64
IdentityFileBase64 types.String `tfsdk:"identity_file_base64"`
// RetryBaseDuration is used to setup the retry algorithm when the API returns 'not found'
RetryBaseDuration types.String `tfsdk:"retry_base_duration"`
// RetryCapDuration is used to setup the retry algorithm when the API returns 'not found'
RetryCapDuration types.String `tfsdk:"retry_cap_duration"`
// RetryMaxTries sets the max number of tries when retrying
RetryMaxTries types.String `tfsdk:"retry_max_tries"`
// DialTimeout sets timeout when trying to connect to the server.
DialTimeoutDuration types.String `tfsdk:"dial_timeout_duration"`
}
// New returns an empty provider struct
func New() tfsdk.Provider {
return &Provider{}
}
// GetSchema returns the Terraform provider schema
func (p *Provider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"addr": {
Type: types.StringType,
Optional: true,
Description: "host:port where Teleport Auth server is running.",
},
"cert_path": {
Type: types.StringType,
Optional: true,
Description: "Path to Teleport auth certificate file.",
},
"cert_base64": {
Type: types.StringType,
Optional: true,
Description: "Base64 encoded TLS auth certificate.",
},
"key_path": {
Type: types.StringType,
Optional: true,
Description: "Path to Teleport auth key file.",
},
"key_base64": {
Type: types.StringType,
Sensitive: true,
Optional: true,
Description: "Base64 encoded TLS auth key.",
},
"root_ca_path": {
Type: types.StringType,
Optional: true,
Description: "Path to Teleport Root CA.",
},
"root_ca_base64": {
Type: types.StringType,
Optional: true,
Description: "Base64 encoded Root CA.",
},
"profile_name": {
Type: types.StringType,
Optional: true,
Description: "Teleport profile name.",
},
"profile_dir": {
Type: types.StringType,
Optional: true,
Description: "Teleport profile path.",
},
"identity_file_path": {
Type: types.StringType,
Optional: true,
Description: "Teleport identity file path.",
},
"identity_file": {
Type: types.StringType,
Sensitive: true,
Optional: true,
Description: "Teleport identity file content.",
},
"identity_file_base64": {
Type: types.StringType,
Sensitive: true,
Optional: true,
Description: "Teleport identity file content base64 encoded.",
},
"retry_base_duration": {
Type: types.StringType,
Sensitive: false,
Optional: true,
Description: "Retry algorithm when the API returns 'not found': base duration between retries (https://pkg.go.dev/time#ParseDuration).",
},
"retry_cap_duration": {
Type: types.StringType,
Sensitive: false,
Optional: true,
Description: "Retry algorithm when the API returns 'not found': max duration between retries (https://pkg.go.dev/time#ParseDuration).",
},
"retry_max_tries": {
Type: types.StringType,
Sensitive: false,
Optional: true,
Description: "Retry algorithm when the API returns 'not found': max tries.",
},
"dial_timeout_duration": {
Type: types.StringType,
Sensitive: false,
Optional: true,
Description: "DialTimeout sets timeout when trying to connect to the server.",
},
},
}, nil
}
// IsConfigured checks if provider is configured, adds diagnostics if not
func (p *Provider) IsConfigured(diags diag.Diagnostics) bool {
if !p.configured {
diags.AddError(
"Provider not configured",
"The provider hasn't been configured before apply, likely because it depends on an unknown value from another resource. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!",
)
}
return p.configured
}
// Configure configures the Teleport client
func (p *Provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderRequest, resp *tfsdk.ConfigureProviderResponse) {
var creds []client.Credentials
p.configureLog()
var config providerData
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
addr := p.stringFromConfigOrEnv(config.Addr, "TF_TELEPORT_ADDR", "")
certPath := p.stringFromConfigOrEnv(config.CertPath, "TF_TELEPORT_CERT", "")
certBase64 := p.stringFromConfigOrEnv(config.CertBase64, "TF_TELEPORT_CERT_BASE64", "")
keyPath := p.stringFromConfigOrEnv(config.KeyPath, "TF_TELEPORT_KEY", "")
keyBase64 := p.stringFromConfigOrEnv(config.KeyBase64, "TF_TELEPORT_KEY_BASE64", "")
caPath := p.stringFromConfigOrEnv(config.RootCaPath, "TF_TELEPORT_ROOT_CA", "")
caBase64 := p.stringFromConfigOrEnv(config.RootCaBase64, "TF_TELEPORT_CA_BASE64", "")
profileName := p.stringFromConfigOrEnv(config.ProfileName, "TF_TELEPORT_PROFILE_NAME", "")
profileDir := p.stringFromConfigOrEnv(config.ProfileDir, "TF_TELEPORT_PROFILE_PATH", "")
identityFilePath := p.stringFromConfigOrEnv(config.IdentityFilePath, "TF_TELEPORT_IDENTITY_FILE_PATH", "")
identityFile := p.stringFromConfigOrEnv(config.IdentityFile, "TF_TELEPORT_IDENTITY_FILE", "")
identityFileBase64 := p.stringFromConfigOrEnv(config.IdentityFileBase64, "TF_TELEPORT_IDENTITY_FILE_BASE64", "")
retryBaseDurationStr := p.stringFromConfigOrEnv(config.RetryBaseDuration, "TF_TELEPORT_RETRY_BASE_DURATION", "1s")
retryCapDurationStr := p.stringFromConfigOrEnv(config.RetryCapDuration, "TF_TELEPORT_RETRY_CAP_DURATION", "5s")
maxTriesStr := p.stringFromConfigOrEnv(config.RetryMaxTries, "TF_TELEPORT_RETRY_MAX_TRIES", "10")
dialTimeoutDurationStr := p.stringFromConfigOrEnv(config.DialTimeoutDuration, "TF_TELEPORT_DIAL_TIMEOUT_DURATION", "30s")
if !p.validateAddr(addr, resp) {
return
}
log.WithFields(log.Fields{"addr": addr}).Debug("Using Teleport address")
if certPath != "" && keyPath != "" {
l := log.WithField("cert_path", certPath).WithField("key_path", keyPath).WithField("root_ca_path", caPath)
l.Debug("Using auth with certificate, private key and (optionally) CA read from files")
cred, ok := p.getCredentialsFromKeyPair(certPath, keyPath, caPath, resp)
if !ok {
return
}
creds = append(creds, cred)
}
if certBase64 != "" && keyBase64 != "" {
log.Debug("Using auth with certificate, private key and (optionally) CA read from base64 encoded vars")
cred, ok := p.getCredentialsFromBase64(certBase64, keyBase64, caBase64, resp)
if !ok {
return
}
creds = append(creds, cred)
}
if identityFilePath != "" {
log.WithField("identity_file_path", identityFilePath).Debug("Using auth with identity file")
if !p.fileExists(identityFilePath) {
resp.Diagnostics.AddError(
"Identity file not found",
fmt.Sprintf(
"File %v not found! Use `tctl auth sign [email protected] --format=file --out=%v` to generate identity file",
identityFilePath,
identityFilePath,
),
)
return
}
creds = append(creds, client.LoadIdentityFile(identityFilePath))
}
if identityFile != "" {
log.Debug("Using auth from identity file provided with environment variable TF_TELEPORT_IDENTITY_FILE")
creds = append(creds, client.LoadIdentityFileFromString(identityFile))
}
if identityFileBase64 != "" {
log.Debug("Using auth from base64 encoded identity file provided with environment variable TF_TELEPORT_IDENTITY_FILE_BASE64")
decoded, err := base64.StdEncoding.DecodeString(identityFileBase64)
if err != nil {
resp.Diagnostics.AddError(
"Failed to decode Identity file using base 64",
fmt.Sprintf("Error when trying to decode: %v", err),
)
return
}
creds = append(creds, client.LoadIdentityFileFromString(string(decoded)))
}
if profileDir != "" || len(creds) == 0 {
log.WithFields(log.Fields{
"dir": profileDir,
"name": profileName,
}).Debug("Using profile as the default auth method")
creds = append(creds, client.LoadProfile(profileDir, profileName))
}
dialTimeoutDuration, err := time.ParseDuration(dialTimeoutDurationStr)
if err != nil {
resp.Diagnostics.AddError(
"Failed to parse Dial Timeout Duration Cap Duration",
fmt.Sprintf("Please check if dial_timeout_duration (or TF_TELEPORT_DIAL_TIMEOUT_DURATION) is set correctly. Error: %s", err),
)
return
}
client, err := client.New(ctx, client.Config{
Addrs: []string{addr},
Credentials: creds,
DialTimeout: dialTimeoutDuration,
DialOpts: []grpc.DialOption{
grpc.WithReturnConnectionError(),
grpc.WithDefaultCallOptions(
grpc.WaitForReady(true),
),
},
})
if err != nil {
log.WithError(err).Debug("Error connecting to Teleport!")
resp.Diagnostics.AddError("Error connecting to Teleport!", err.Error())
return
}
if !p.checkTeleportVersion(ctx, client, resp) {
return
}
retryBaseDuration, err := time.ParseDuration(retryBaseDurationStr)
if err != nil {
resp.Diagnostics.AddError(
"Failed to parse Retry Base Duration",
fmt.Sprintf("Please check if retry_cap_duration (or TF_TELEPORT_RETRY_BASE_DURATION) is set correctly. Error: %s", err),
)
return
}
retryCapDuration, err := time.ParseDuration(retryCapDurationStr)
if err != nil {
resp.Diagnostics.AddError(
"Failed to parse Retry Cap Duration",
fmt.Sprintf("Please check if retry_cap_duration (or TF_TELEPORT_RETRY_CAP_DURATION) is set correctly. Error: %s", err),
)
return
}
maxTries, err := strconv.ParseUint(maxTriesStr, 10, 32)
if err != nil {
resp.Diagnostics.AddError(
"Failed to parse Retry Max Tries",
fmt.Sprintf("Please check if retry_max_tries (or TF_TELEPORT_RETRY_MAX_TRIES) is set correctly. Error: %s", err),
)
return
}
p.RetryConfig = RetryConfig{
Base: retryBaseDuration,
Cap: retryCapDuration,
MaxTries: int(maxTries),
}
p.Client = client
p.configured = true
}
// checkTeleportVersion ensures that Teleport version is at least minServerVersion
func (p *Provider) checkTeleportVersion(ctx context.Context, client *client.Client, resp *tfsdk.ConfigureProviderResponse) bool {
log.Debug("Checking Teleport server version")
pong, err := client.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
resp.Diagnostics.AddError(
"Teleport version is too old!",
fmt.Sprintf("Server version must be at least %s", minServerVersion),
)
return false
}
log.WithError(err).Debug("Teleport version check error!")
resp.Diagnostics.AddError("Unable to get Teleport server version!", "Unable to get Teleport server version!")
return false
}
err = lib.AssertServerVersion(pong, minServerVersion)
if err != nil {
log.WithError(err).Debug("Teleport version check error!")
resp.Diagnostics.AddError("Teleport version check error!", err.Error())
return false
}
return true
}
// stringFromConfigOrEnv returns value from config or from env var if config value is empty, default otherwise
func (p *Provider) stringFromConfigOrEnv(value types.String, env string, def string) string {
if value.Unknown || value.Null {
value := os.Getenv(env)
if value != "" {
return value
}
}
configValue := strings.TrimSpace(value.Value)
if configValue == "" {
return def
}
return configValue
}
// validateAddr validates passed addr
func (p *Provider) validateAddr(addr string, resp *tfsdk.ConfigureProviderResponse) bool {
if addr == "" {
resp.Diagnostics.AddError(
"Teleport address is empty",
"Please, specify either TF_TELEPORT_ADDR or addr in provider configuration",
)
return false
}
_, _, err := net.SplitHostPort(addr)
if err != nil {
log.WithField("addr", addr).WithError(err).Debug("Teleport addr format error!")
resp.Diagnostics.AddError(
"Invalid Teleport addr format",
"Teleport addr must be specified as host:port",
)
return false
}
return true
}
// getCredentialsFromBase64 returns client.Credentials built from base64 encoded keys
func (p *Provider) getCredentialsFromBase64(certBase64, keyBase64, caBase64 string, resp *tfsdk.ConfigureProviderResponse) (client.Credentials, bool) {
cert, err := base64.StdEncoding.DecodeString(certBase64)
if err != nil {
resp.Diagnostics.AddError(
"Failed to base64 decode cert",
fmt.Sprintf("Please check if cert_base64 (or TF_TELEPORT_CERT_BASE64) is set correctly. Error: %s", err),
)
return nil, false
}
key, err := base64.StdEncoding.DecodeString(keyBase64)
if err != nil {
resp.Diagnostics.AddError(
"Failed to base64 decode key",
fmt.Sprintf("Please check if key_base64 (or TF_TELEPORT_KEY_BASE64) is set correctly. Error: %s", err),
)
return nil, false
}
rootCa, err := base64.StdEncoding.DecodeString(caBase64)
if err != nil {
resp.Diagnostics.AddError(
"Failed to base64 decode root ca",
fmt.Sprintf("Please check if root_ca_base64 (or TF_TELEPORT_CA_BASE64) is set correctly. Error: %s", err),
)
return nil, false
}
tlsConfig, err := createTLSConfig(cert, key, rootCa)
if err != nil {
resp.Diagnostics.AddError(
"Failed to create TLS config",
fmt.Sprintf("Error: %s", err),
)
return nil, false
}
return client.LoadTLS(tlsConfig), true
}
// getCredentialsFromKeyPair returns client.Credentials built from path to key files
func (p *Provider) getCredentialsFromKeyPair(certPath string, keyPath string, caPath string, resp *tfsdk.ConfigureProviderResponse) (client.Credentials, bool) {
if !p.fileExists(certPath) {
resp.Diagnostics.AddError(
"Certificate file not found",
fmt.Sprintf("File %v not found! Use 'tctl auth sign [email protected] --format=tls --out=%v' to generate keys",
certPath,
filepath.Dir(certPath),
),
)
return nil, false
}
if !p.fileExists(keyPath) {
resp.Diagnostics.AddError(
"Private key file not found",
fmt.Sprintf("File %v not found! Use 'tctl auth sign [email protected] --format=tls --out=%v' to generate keys",
keyPath,
filepath.Dir(keyPath),
),
)
return nil, false
}
if !p.fileExists(caPath) {
resp.Diagnostics.AddError(
"Root CA certificate file not found",
fmt.Sprintf("File %v not found! Use 'tctl auth sign [email protected] --format=tls --out=%v' to generate keys",
caPath,
filepath.Dir(caPath),
),
)
return nil, false
}
return client.LoadKeyPair(certPath, keyPath, caPath), true
}
// fileExists returns true if file exists
func (p *Provider) fileExists(path string) bool {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
if err != nil {
return false
}
return true
}
// configureLog configures logging
func (p *Provider) configureLog() {
// Get Terraform log level
level, err := log.ParseLevel(os.Getenv("TF_LOG"))
if err != nil {
log.SetLevel(log.ErrorLevel)
} else {
log.SetLevel(level)
}
log.SetFormatter(&log.TextFormatter{})
// Show GRPC debug logs only if TF_LOG=DEBUG
if log.GetLevel() >= log.DebugLevel {
l := grpclog.NewLoggerV2(log.StandardLogger().Out, log.StandardLogger().Out, log.StandardLogger().Out)
grpclog.SetLoggerV2(l)
}
}
// createTLSConfig returns tls.Config build from keys
func createTLSConfig(cert, key, rootCa []byte) (*tls.Config, error) {
keyPair, err := tls.X509KeyPair(cert, key)
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(rootCa)
return &tls.Config{
Certificates: []tls.Certificate{keyPair},
RootCAs: caCertPool,
}, nil
}
// GetResources returns the map of provider resources
func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) {
return map[string]tfsdk.ResourceType{
"teleport_app": resourceTeleportAppType{},
"teleport_auth_preference": resourceTeleportAuthPreferenceType{},
"teleport_cluster_maintenance_config": resourceTeleportClusterMaintenanceConfigType{},
"teleport_cluster_networking_config": resourceTeleportClusterNetworkingConfigType{},
"teleport_database": resourceTeleportDatabaseType{},
"teleport_github_connector": resourceTeleportGithubConnectorType{},
"teleport_provision_token": resourceTeleportProvisionTokenType{},
"teleport_oidc_connector": resourceTeleportOIDCConnectorType{},
"teleport_role": resourceTeleportRoleType{},
"teleport_saml_connector": resourceTeleportSAMLConnectorType{},
"teleport_session_recording_config": resourceTeleportSessionRecordingConfigType{},
"teleport_trusted_cluster": resourceTeleportTrustedClusterType{},
"teleport_user": resourceTeleportUserType{},
"teleport_bot": resourceTeleportBotType{},
"teleport_login_rule": resourceTeleportLoginRuleType{},
"teleport_trusted_device": resourceTeleportDeviceV1Type{},
"teleport_okta_import_rule": resourceTeleportOktaImportRuleType{},
"teleport_access_list": resourceTeleportAccessListType{},
"teleport_server": resourceTeleportServerType{},
}, nil
}
// GetDataSources returns the map of provider data sources
func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourceType, diag.Diagnostics) {
return map[string]tfsdk.DataSourceType{
"teleport_app": dataSourceTeleportAppType{},
"teleport_auth_preference": dataSourceTeleportAuthPreferenceType{},
"teleport_cluster_maintenance_config": dataSourceTeleportClusterMaintenanceConfigType{},
"teleport_cluster_networking_config": dataSourceTeleportClusterNetworkingConfigType{},
"teleport_database": dataSourceTeleportDatabaseType{},
"teleport_github_connector": dataSourceTeleportGithubConnectorType{},
"teleport_provision_token": dataSourceTeleportProvisionTokenType{},
"teleport_oidc_connector": dataSourceTeleportOIDCConnectorType{},
"teleport_role": dataSourceTeleportRoleType{},
"teleport_saml_connector": dataSourceTeleportSAMLConnectorType{},
"teleport_session_recording_config": dataSourceTeleportSessionRecordingConfigType{},
"teleport_trusted_cluster": dataSourceTeleportTrustedClusterType{},
"teleport_user": dataSourceTeleportUserType{},
"teleport_login_rule": dataSourceTeleportLoginRuleType{},
"teleport_trusted_device": dataSourceTeleportDeviceV1Type{},
"teleport_okta_import_rule": dataSourceTeleportOktaImportRuleType{},
"teleport_access_list": dataSourceTeleportAccessListType{},
}, nil
}
@@ -0,0 +1,332 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
accesslist "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
convert "github.com/gravitational/teleport/api/types/accesslist/convert/v1"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/accesslist/v1"
)
// resourceTeleportAccessListType is the resource metadata type
type resourceTeleportAccessListType struct{}
// resourceTeleportAccessList is the resource
type resourceTeleportAccessList struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportAccessListType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaAccessList(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportAccessListType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportAccessList{
p: *(p.(*Provider)),
}, nil
}
// Create creates the AccessList
func (r resourceTeleportAccessList) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessList := &accesslist.AccessList{}
diags = schemav1.CopyAccessListFromTerraform(ctx, plan, accessList)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessListResource, err := convert.FromProto(accessList)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Errorf("Can not convert %T to AccessList: %s", accessListResource, err), "access_list"))
return
}
err = accessListResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting AccessList defaults", trace.Wrap(err), "access_list"))
return
}
id := accessListResource.Metadata.Name
_, err = r.p.Client.AccessListClient().GetAccessList(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("AccessList exists in Teleport. Either remove it (tctl rm access_list/%v)"+
" or import it to the existing state (terraform import teleport_access_list.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("AccessList exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
_, err = r.p.Client.AccessListClient().UpsertAccessList(ctx, accessListResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating AccessList", trace.Wrap(err), "access_list"))
return
}
var accessListI = accessListResource
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
accessListI, err = r.p.Client.AccessListClient().GetAccessList(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(bErr), "access_list"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading AccessList (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "access_list")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
accessListResource = accessListI
accessList = convert.ToProto(accessListResource)
diags = schemav1.CopyAccessListToTerraform(ctx, accessList, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: accessList.Header.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport AccessList
func (r resourceTeleportAccessList) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessListI, err := r.p.Client.AccessListClient().GetAccessList(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
accessList := convert.ToProto(accessListI)
diags = schemav1.CopyAccessListToTerraform(ctx, accessList, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport AccessList
func (r resourceTeleportAccessList) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessList := &accesslist.AccessList{}
diags = schemav1.CopyAccessListFromTerraform(ctx, plan, accessList)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
accessListResource, err := convert.FromProto(accessList)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Errorf("Can not convert %T to AccessList: %s", accessListResource, err), "access_list"))
return
}
if err := accessListResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating AccessList", err, "access_list"))
return
}
name := accessListResource.Metadata.Name
accessListBefore, err := r.p.Client.AccessListClient().GetAccessList(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", err, "access_list"))
return
}
accessListResource.Spec.Audit.NextAuditDate = accessListBefore.Spec.Audit.NextAuditDate
_, err = r.p.Client.AccessListClient().UpsertAccessList(ctx, accessListResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating AccessList", err, "access_list"))
return
}
var accessListI = accessListResource
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
accessListI, err = r.p.Client.AccessListClient().GetAccessList(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", err, "access_list"))
return
}
if accessListBefore.GetMetadata().Revision != accessListI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading AccessList (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "access_list")
return
}
}
accessListResource = accessListI
diags = schemav1.CopyAccessListToTerraform(ctx, accessList, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport AccessList
func (r resourceTeleportAccessList) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("header").AtName("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.AccessListClient().DeleteAccessList(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting AccessList", trace.Wrap(err), "access_list"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports AccessList state
func (r resourceTeleportAccessList) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
accessList, err := r.p.Client.AccessListClient().GetAccessList(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AccessList", trace.Wrap(err), "access_list"))
return
}
accessListResource := convert.ToProto(accessList)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = schemav1.CopyAccessListToTerraform(ctx, accessListResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := accessList.Metadata.Name
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+335
View File
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportAppType is the resource metadata type
type resourceTeleportAppType struct{}
// resourceTeleportApp is the resource
type resourceTeleportApp struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportAppType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaAppV3(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportAppType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportApp{
p: *(p.(*Provider)),
}, nil
}
// Create creates the App
func (r resourceTeleportApp) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
app := &apitypes.AppV3{}
diags = tfschema.CopyAppV3FromTerraform(ctx, plan, app)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
appResource := app
err = appResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting App defaults", trace.Wrap(err), "app"))
return
}
id := appResource.Metadata.Name
_, err = r.p.Client.GetApp(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("App exists in Teleport. Either remove it (tctl rm app/%v)"+
" or import it to the existing state (terraform import teleport_app.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("App exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
err = r.p.Client.CreateApp(ctx, appResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating App", trace.Wrap(err), "app"))
return
}
// Not really an inferface, just using the same name for easier templating.
var appI apitypes.Application
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
appI, err = r.p.Client.GetApp(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(bErr), "app"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading App (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "app")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
appResource, ok := appI.(*apitypes.AppV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Errorf("Can not convert %T to AppV3", appI), "app"))
return
}
app = appResource
diags = tfschema.CopyAppV3ToTerraform(ctx, app, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: app.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport App
func (r resourceTeleportApp) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
appI, err := r.p.Client.GetApp(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
app := appI.(*apitypes.AppV3)
diags = tfschema.CopyAppV3ToTerraform(ctx, app, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport App
func (r resourceTeleportApp) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
app := &apitypes.AppV3{}
diags = tfschema.CopyAppV3FromTerraform(ctx, plan, app)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
appResource := app
if err := appResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating App", err, "app"))
return
}
name := appResource.Metadata.Name
appBefore, err := r.p.Client.GetApp(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", err, "app"))
return
}
err = r.p.Client.UpdateApp(ctx, appResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating App", err, "app"))
return
}
// Not really an inferface, just using the same name for easier templating.
var appI apitypes.Application
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
appI, err = r.p.Client.GetApp(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", err, "app"))
return
}
if appBefore.GetMetadata().Revision != appI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading App (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "app")
return
}
}
appResource, ok := appI.(*apitypes.AppV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Errorf("Can not convert %T to AppV3", appI), "app"))
return
}
diags = tfschema.CopyAppV3ToTerraform(ctx, app, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport App
func (r resourceTeleportApp) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteApp(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting AppV3", trace.Wrap(err), "app"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports App state
func (r resourceTeleportApp) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
app, err := r.p.Client.GetApp(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading App", trace.Wrap(err), "app"))
return
}
appResource := app.(*apitypes.AppV3)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyAppV3ToTerraform(ctx, appResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := appResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,300 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportAuthPreferenceType is the resource metadata type
type resourceTeleportAuthPreferenceType struct{}
// resourceTeleportAuthPreference is the resource
type resourceTeleportAuthPreference struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportAuthPreferenceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaAuthPreferenceV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportAuthPreferenceType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportAuthPreference{
p: *(p.(*Provider)),
}, nil
}
// Create creates the AuthPreference
func (r resourceTeleportAuthPreference) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
authPreference := &apitypes.AuthPreferenceV2{}
diags = tfschema.CopyAuthPreferenceV2FromTerraform(ctx, plan, authPreference)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := authPreference.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting AuthPreference defaults", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreferenceBefore, err := r.p.Client.GetAuthPreference(ctx)
if err != nil && !trace.IsNotFound(err) {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
err = r.p.Client.SetAuthPreference(ctx, authPreference)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
var authPreferenceI apitypes.AuthPreference
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
authPreferenceI, err = r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
if authPreferenceBefore.GetMetadata().Revision != authPreferenceI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(bErr), "cluster_auth_preference"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading AuthPreference (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_auth_preference")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreference, ok := authPreferenceI.(*apitypes.AuthPreferenceV2)
if !ok {
resp.Diagnostics.Append(
diagFromWrappedErr("Error reading AuthPreference", trace.Errorf("Can not convert %T to AuthPreferenceV2", authPreferenceI), "cluster_auth_preference"),
)
return
}
diags = tfschema.CopyAuthPreferenceV2ToTerraform(ctx, authPreference, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: "auth_preference"}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport AuthPreference
func (r resourceTeleportAuthPreference) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
authPreferenceI, err := r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreference := authPreferenceI.(*apitypes.AuthPreferenceV2)
diags = tfschema.CopyAuthPreferenceV2ToTerraform(ctx, authPreference, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport AuthPreference
func (r resourceTeleportAuthPreference) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
authPreference := &apitypes.AuthPreferenceV2{}
diags = tfschema.CopyAuthPreferenceV2FromTerraform(ctx, plan, authPreference)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := authPreference.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreferenceBefore, err := r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
err = r.p.Client.SetAuthPreference(ctx, authPreference)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
var authPreferenceI apitypes.AuthPreference
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
authPreferenceI, err = r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
if authPreferenceBefore.GetMetadata().Revision != authPreferenceI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(bErr), "cluster_auth_preference"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading AuthPreference (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_auth_preference")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreference = authPreferenceI.(*apitypes.AuthPreferenceV2)
diags = tfschema.CopyAuthPreferenceV2ToTerraform(ctx, authPreference, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport AuthPreference
func (r resourceTeleportAuthPreference) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
err := r.p.Client.ResetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports AuthPreference state
func (r resourceTeleportAuthPreference) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
authPreferenceI, err := r.p.Client.GetAuthPreference(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating AuthPreference", trace.Wrap(err), "cluster_auth_preference"))
return
}
authPreference := authPreferenceI.(*apitypes.AuthPreferenceV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyAuthPreferenceV2ToTerraform(ctx, authPreference, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
state.Attrs["id"] = types.String{Value: authPreference.Metadata.Name}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,255 @@
/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
"github.com/gravitational/teleport/api/utils"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
func GenSchemaBot(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"id": {
Type: types.StringType,
Computed: true,
},
"name": {
Type: types.StringType,
Required: true,
Description: "The name of the bot, i.e. the unprefixed User name",
PlanModifiers: []tfsdk.AttributePlanModifier{
tfsdk.RequiresReplace(),
},
},
"user_name": {
Type: types.StringType,
Computed: true,
Description: "The name of the generated bot user",
},
"role_name": {
Type: types.StringType,
Computed: true,
Description: "The name of the generated bot role",
},
"token_ttl": {
Type: types.StringType,
Optional: true,
Computed: true,
Description: "Deprecated. This field is not required anymore and has no effect.",
},
"token_id": {
Type: types.StringType,
// Implementation note: this is not used anymore, we can skip this
// This will go away eventually when we'll generate the bot provider instead
Optional: true,
Sensitive: true,
Description: "Deprecated. This field is not required anymore and has no effect.",
},
"roles": {
Type: types.ListType{
ElemType: types.StringType,
},
Required: true,
Description: "A list of roles the created bot should be allowed to assume via role impersonation.",
// TODO: Consider dropping RequiresReplace() in the future if a
// UpdateBotRoles() API becomes available that can modify the
// underlying bot user.
PlanModifiers: []tfsdk.AttributePlanModifier{
tfsdk.RequiresReplace(),
},
},
// Implementation note: This needs RequiresReplace() to handle
// updates properly but we aren't able to attach plan modifiers to
// fields from schema methods here. See ModifyPlan below.
"traits": tfschema.GenSchemaTraits(ctx),
},
}, nil
}
// Bot is a deserializes representation of the terraform state for this
// resource.
type Bot struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Roles []types.String `tfsdk:"roles"`
TokenID types.String `tfsdk:"token_id"`
Traits types.Map `tfsdk:"traits"`
TTL types.String `tfsdk:"token_ttl"`
UserName types.String `tfsdk:"user_name"`
RoleName types.String `tfsdk:"role_name"`
}
// resourceTeleportBotType is the resource metadata type
type resourceTeleportBotType struct{}
// GetSchema returns the resource schema
func (r resourceTeleportBotType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
// It's unusual for this provider, but we'll hand-write the schema here as
// bots do not have any server-side resources of their own.
return GenSchemaBot(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportBotType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportBot{
p: *(p.(*Provider)),
}, nil
}
// resourceTeleportBot is the resource
type resourceTeleportBot struct {
p Provider
}
func (r resourceTeleportBot) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan Bot
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var roles []string
for _, role := range plan.Roles {
roles = append(roles, role.Value)
}
traits := make([]*machineidv1.Trait, 0, len(plan.Traits.Elems))
for name, e := range plan.Traits.Elems {
l, ok := e.(types.List)
if !ok {
diags.AddError("Error reading from Terraform object", fmt.Sprintf("Can not convert %T to types.List", l))
return
}
values := make(utils.Strings, len(l.Elems))
for i, v := range l.Elems {
s, ok := v.(types.String)
if !ok {
diags.AddError("Error reading from Terraform object", fmt.Sprintf("Can not convert %T to types.String", s))
return
}
values[i] = s.Value
}
traits = append(traits, &machineidv1.Trait{
Name: name,
Values: values,
})
}
// This is a temporary workaround to fix the provider compilation in v16 (the legacy RPC got removed).
// We must do a breaking change in v16 and rely on the new bot schema and the tf code generator.
response, err := r.p.Client.BotServiceClient().CreateBot(ctx, &machineidv1.CreateBotRequest{Bot: &machineidv1.Bot{
Metadata: &headerv1.Metadata{
Name: plan.Name.Value,
},
Spec: &machineidv1.BotSpec{
Roles: roles,
Traits: traits,
},
}})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating Bot", trace.Wrap(err), "bot"))
return
}
plan.TTL = types.String{Value: ""}
plan.UserName = types.String{Value: response.Status.UserName}
plan.RoleName = types.String{Value: response.Status.RoleName}
// ID is for terraform-plugin-framework's acctests
plan.ID = types.String{Value: plan.Name.Value}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
func (r resourceTeleportBot) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
// Not much to do here: bots are currently immutable. We'll just check for
// deletion.
var plan Bot
diags := req.State.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
_, err := r.p.Client.GetUser(ctx, plan.UserName.Value, false)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Bot", trace.Wrap(err), "bot"))
return
}
}
func (r resourceTeleportBot) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
// Nothing to do here: bots are currently immutable. In the future we'd
// ideally want to add specific RPCs for desired mutable attributes, e.g.
// UpdateBotRoles(), UpdateBotToken(), etc.
}
func (r resourceTeleportBot) ModifyPlan(ctx context.Context, req tfsdk.ModifyResourcePlanRequest, resp *tfsdk.ModifyResourcePlanResponse) {
// Add .traits to RequiresReplace to ensure changes to this field trigger a
// replacement. We can't set it in the schema as the attribute is generated
// by a helper method.
resp.RequiresReplace = append(resp.RequiresReplace, path.Root("traits"))
}
func (r resourceTeleportBot) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var name types.String
diags := req.State.GetAttribute(ctx, path.Root("name"), &name)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
_, err := r.p.Client.BotServiceClient().DeleteBot(ctx, &machineidv1.DeleteBotRequest{BotName: name.Value})
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting Bot", trace.Wrap(err), "bot"))
return
}
resp.State.RemoveResource(ctx)
}
@@ -0,0 +1,307 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
"math"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportClusterMaintenanceConfigType is the resource metadata type
type resourceTeleportClusterMaintenanceConfigType struct{}
// resourceTeleportClusterMaintenanceConfig is the resource
type resourceTeleportClusterMaintenanceConfig struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportClusterMaintenanceConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaClusterMaintenanceConfigV1(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportClusterMaintenanceConfigType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportClusterMaintenanceConfig{
p: *(p.(*Provider)),
}, nil
}
// Create creates the ClusterMaintenanceConfig
func (r resourceTeleportClusterMaintenanceConfig) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterMaintenanceConfig := &apitypes.ClusterMaintenanceConfigV1{}
diags = tfschema.CopyClusterMaintenanceConfigV1FromTerraform(ctx, plan, clusterMaintenanceConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := clusterMaintenanceConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting ClusterMaintenanceConfig defaults", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfigBefore, err := r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil && !trace.IsNotFound(err) {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
if clusterMaintenanceConfigBefore == nil {
clusterMaintenanceConfigBefore = &apitypes.ClusterMaintenanceConfigV1{}
}
clusterMaintenanceConfig = clusterMaintenanceConfig.WithNonce(math.MaxUint64).(*apitypes.ClusterMaintenanceConfigV1)
err = r.p.Client.UpdateClusterMaintenanceConfig(ctx, clusterMaintenanceConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
var clusterMaintenanceConfigI apitypes.ClusterMaintenanceConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
clusterMaintenanceConfigI, err = r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
if clusterMaintenanceConfigBefore.GetMetadata().Revision != clusterMaintenanceConfigI.GetMetadata().Revision || true {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(bErr), "cluster_maintenance_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ClusterMaintenanceConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_maintenance_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfig, ok := clusterMaintenanceConfigI.(*apitypes.ClusterMaintenanceConfigV1)
if !ok {
resp.Diagnostics.Append(
diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Errorf("Can not convert %T to ClusterMaintenanceConfigV1", clusterMaintenanceConfigI), "cluster_maintenance_config"),
)
return
}
diags = tfschema.CopyClusterMaintenanceConfigV1ToTerraform(ctx, clusterMaintenanceConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: "cluster_maintenance_config"}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport ClusterMaintenanceConfig
func (r resourceTeleportClusterMaintenanceConfig) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterMaintenanceConfigI, err := r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfig := clusterMaintenanceConfigI.(*apitypes.ClusterMaintenanceConfigV1)
diags = tfschema.CopyClusterMaintenanceConfigV1ToTerraform(ctx, clusterMaintenanceConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport ClusterMaintenanceConfig
func (r resourceTeleportClusterMaintenanceConfig) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterMaintenanceConfig := &apitypes.ClusterMaintenanceConfigV1{}
diags = tfschema.CopyClusterMaintenanceConfigV1FromTerraform(ctx, plan, clusterMaintenanceConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := clusterMaintenanceConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfigBefore, err := r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfig = clusterMaintenanceConfig.WithNonce(math.MaxUint64).(*apitypes.ClusterMaintenanceConfigV1)
err = r.p.Client.UpdateClusterMaintenanceConfig(ctx, clusterMaintenanceConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
var clusterMaintenanceConfigI apitypes.ClusterMaintenanceConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
clusterMaintenanceConfigI, err = r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
if clusterMaintenanceConfigBefore.GetMetadata().Revision != clusterMaintenanceConfigI.GetMetadata().Revision || true {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(bErr), "cluster_maintenance_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ClusterMaintenanceConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_maintenance_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfig = clusterMaintenanceConfigI.(*apitypes.ClusterMaintenanceConfigV1)
diags = tfschema.CopyClusterMaintenanceConfigV1ToTerraform(ctx, clusterMaintenanceConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport ClusterMaintenanceConfig
func (r resourceTeleportClusterMaintenanceConfig) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
err := r.p.Client.DeleteClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports ClusterMaintenanceConfig state
func (r resourceTeleportClusterMaintenanceConfig) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
clusterMaintenanceConfigI, err := r.p.Client.GetClusterMaintenanceConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterMaintenanceConfig", trace.Wrap(err), "cluster_maintenance_config"))
return
}
clusterMaintenanceConfig := clusterMaintenanceConfigI.(*apitypes.ClusterMaintenanceConfigV1)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyClusterMaintenanceConfigV1ToTerraform(ctx, clusterMaintenanceConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
state.Attrs["id"] = types.String{Value: clusterMaintenanceConfig.Metadata.Name}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,300 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportClusterNetworkingConfigType is the resource metadata type
type resourceTeleportClusterNetworkingConfigType struct{}
// resourceTeleportClusterNetworkingConfig is the resource
type resourceTeleportClusterNetworkingConfig struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportClusterNetworkingConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaClusterNetworkingConfigV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportClusterNetworkingConfigType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportClusterNetworkingConfig{
p: *(p.(*Provider)),
}, nil
}
// Create creates the ClusterNetworkingConfig
func (r resourceTeleportClusterNetworkingConfig) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterNetworkingConfig := &apitypes.ClusterNetworkingConfigV2{}
diags = tfschema.CopyClusterNetworkingConfigV2FromTerraform(ctx, plan, clusterNetworkingConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := clusterNetworkingConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting ClusterNetworkingConfig defaults", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfigBefore, err := r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil && !trace.IsNotFound(err) {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
err = r.p.Client.SetClusterNetworkingConfig(ctx, clusterNetworkingConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
var clusterNetworkingConfigI apitypes.ClusterNetworkingConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
clusterNetworkingConfigI, err = r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
if clusterNetworkingConfigBefore.GetMetadata().Revision != clusterNetworkingConfigI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(bErr), "cluster_networking_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ClusterNetworkingConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_networking_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfig, ok := clusterNetworkingConfigI.(*apitypes.ClusterNetworkingConfigV2)
if !ok {
resp.Diagnostics.Append(
diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Errorf("Can not convert %T to ClusterNetworkingConfigV2", clusterNetworkingConfigI), "cluster_networking_config"),
)
return
}
diags = tfschema.CopyClusterNetworkingConfigV2ToTerraform(ctx, clusterNetworkingConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: "cluster_networking_config"}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport ClusterNetworkingConfig
func (r resourceTeleportClusterNetworkingConfig) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterNetworkingConfigI, err := r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfig := clusterNetworkingConfigI.(*apitypes.ClusterNetworkingConfigV2)
diags = tfschema.CopyClusterNetworkingConfigV2ToTerraform(ctx, clusterNetworkingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport ClusterNetworkingConfig
func (r resourceTeleportClusterNetworkingConfig) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
clusterNetworkingConfig := &apitypes.ClusterNetworkingConfigV2{}
diags = tfschema.CopyClusterNetworkingConfigV2FromTerraform(ctx, plan, clusterNetworkingConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := clusterNetworkingConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfigBefore, err := r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
err = r.p.Client.SetClusterNetworkingConfig(ctx, clusterNetworkingConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
var clusterNetworkingConfigI apitypes.ClusterNetworkingConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
clusterNetworkingConfigI, err = r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
if clusterNetworkingConfigBefore.GetMetadata().Revision != clusterNetworkingConfigI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(bErr), "cluster_networking_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ClusterNetworkingConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "cluster_networking_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfig = clusterNetworkingConfigI.(*apitypes.ClusterNetworkingConfigV2)
diags = tfschema.CopyClusterNetworkingConfigV2ToTerraform(ctx, clusterNetworkingConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport ClusterNetworkingConfig
func (r resourceTeleportClusterNetworkingConfig) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
err := r.p.Client.ResetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports ClusterNetworkingConfig state
func (r resourceTeleportClusterNetworkingConfig) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
clusterNetworkingConfigI, err := r.p.Client.GetClusterNetworkingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ClusterNetworkingConfig", trace.Wrap(err), "cluster_networking_config"))
return
}
clusterNetworkingConfig := clusterNetworkingConfigI.(*apitypes.ClusterNetworkingConfigV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyClusterNetworkingConfigV2ToTerraform(ctx, clusterNetworkingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
state.Attrs["id"] = types.String{Value: clusterNetworkingConfig.Metadata.Name}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportDatabaseType is the resource metadata type
type resourceTeleportDatabaseType struct{}
// resourceTeleportDatabase is the resource
type resourceTeleportDatabase struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportDatabaseType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaDatabaseV3(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportDatabaseType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportDatabase{
p: *(p.(*Provider)),
}, nil
}
// Create creates the Database
func (r resourceTeleportDatabase) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
database := &apitypes.DatabaseV3{}
diags = tfschema.CopyDatabaseV3FromTerraform(ctx, plan, database)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
databaseResource := database
err = databaseResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting Database defaults", trace.Wrap(err), "db"))
return
}
id := databaseResource.Metadata.Name
_, err = r.p.Client.GetDatabase(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("Database exists in Teleport. Either remove it (tctl rm db/%v)"+
" or import it to the existing state (terraform import teleport_database.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("Database exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
err = r.p.Client.CreateDatabase(ctx, databaseResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating Database", trace.Wrap(err), "db"))
return
}
// Not really an inferface, just using the same name for easier templating.
var databaseI apitypes.Database
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
databaseI, err = r.p.Client.GetDatabase(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(bErr), "db"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Database (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "db")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
databaseResource, ok := databaseI.(*apitypes.DatabaseV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Errorf("Can not convert %T to DatabaseV3", databaseI), "db"))
return
}
database = databaseResource
diags = tfschema.CopyDatabaseV3ToTerraform(ctx, database, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: database.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport Database
func (r resourceTeleportDatabase) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
databaseI, err := r.p.Client.GetDatabase(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
database := databaseI.(*apitypes.DatabaseV3)
diags = tfschema.CopyDatabaseV3ToTerraform(ctx, database, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport Database
func (r resourceTeleportDatabase) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
database := &apitypes.DatabaseV3{}
diags = tfschema.CopyDatabaseV3FromTerraform(ctx, plan, database)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
databaseResource := database
if err := databaseResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Database", err, "db"))
return
}
name := databaseResource.Metadata.Name
databaseBefore, err := r.p.Client.GetDatabase(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", err, "db"))
return
}
err = r.p.Client.UpdateDatabase(ctx, databaseResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Database", err, "db"))
return
}
// Not really an inferface, just using the same name for easier templating.
var databaseI apitypes.Database
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
databaseI, err = r.p.Client.GetDatabase(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", err, "db"))
return
}
if databaseBefore.GetMetadata().Revision != databaseI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Database (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "db")
return
}
}
databaseResource, ok := databaseI.(*apitypes.DatabaseV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Errorf("Can not convert %T to DatabaseV3", databaseI), "db"))
return
}
diags = tfschema.CopyDatabaseV3ToTerraform(ctx, database, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport Database
func (r resourceTeleportDatabase) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteDatabase(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting DatabaseV3", trace.Wrap(err), "db"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports Database state
func (r resourceTeleportDatabase) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
database, err := r.p.Client.GetDatabase(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
databaseResource := database.(*apitypes.DatabaseV3)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyDatabaseV3ToTerraform(ctx, databaseResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := databaseResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,320 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
"github.com/google/uuid"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/devicetrust/v1"
)
// resourceTeleportDeviceV1Type is the resource metadata type
type resourceTeleportDeviceV1Type struct{}
// resourceTeleportDeviceV1 is the resource
type resourceTeleportDeviceV1 struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportDeviceV1Type) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaDeviceV1(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportDeviceV1Type) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportDeviceV1{
p: *(p.(*Provider)),
}, nil
}
// Create creates the DeviceV1
func (r resourceTeleportDeviceV1) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedDevice := &apitypes.DeviceV1{}
diags = schemav1.CopyDeviceV1FromTerraform(ctx, plan, trustedDevice)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
if trustedDevice.Metadata.Name == "" {
trustedDevice.Metadata.Name = uuid.NewString()
}
trustedDeviceResource := trustedDevice
id := trustedDeviceResource.Metadata.Name
_, err = r.p.Client.GetDeviceResource(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("DeviceV1 exists in Teleport. Either remove it (tctl rm device/%v)"+
" or import it to the existing state (terraform import teleport_device_trust.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("DeviceV1 exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
_, err = r.p.Client.UpsertDeviceResource(ctx, trustedDeviceResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating DeviceV1", trace.Wrap(err), "device"))
return
}
var trustedDeviceI *apitypes.DeviceV1
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
trustedDeviceI, err = r.p.Client.GetDeviceResource(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(bErr), "device"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading DeviceV1 (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "device")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
trustedDeviceResource = trustedDeviceI
trustedDevice = trustedDeviceResource
diags = schemav1.CopyDeviceV1ToTerraform(ctx, trustedDevice, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: trustedDevice.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport DeviceV1
func (r resourceTeleportDeviceV1) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedDeviceI, err := r.p.Client.GetDeviceResource(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
trustedDevice := trustedDeviceI
diags = schemav1.CopyDeviceV1ToTerraform(ctx, trustedDevice, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport DeviceV1
func (r resourceTeleportDeviceV1) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedDevice := &apitypes.DeviceV1{}
diags = schemav1.CopyDeviceV1FromTerraform(ctx, plan, trustedDevice)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedDeviceResource := trustedDevice
name := trustedDeviceResource.Metadata.Name
trustedDeviceBefore, err := r.p.Client.GetDeviceResource(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", err, "device"))
return
}
_, err = r.p.Client.UpsertDeviceResource(ctx, trustedDeviceResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating DeviceV1", err, "device"))
return
}
var trustedDeviceI *apitypes.DeviceV1
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
trustedDeviceI, err = r.p.Client.GetDeviceResource(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", err, "device"))
return
}
if trustedDeviceBefore.GetMetadata().Revision != trustedDeviceI.GetMetadata().Revision || true {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading DeviceV1 (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "device")
return
}
}
trustedDeviceResource = trustedDeviceI
diags = schemav1.CopyDeviceV1ToTerraform(ctx, trustedDevice, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport DeviceV1
func (r resourceTeleportDeviceV1) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteDeviceResource(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting DeviceV1", trace.Wrap(err), "device"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports DeviceV1 state
func (r resourceTeleportDeviceV1) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
trustedDevice, err := r.p.Client.GetDeviceResource(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading DeviceV1", trace.Wrap(err), "device"))
return
}
trustedDeviceResource := trustedDevice
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = schemav1.CopyDeviceV1ToTerraform(ctx, trustedDeviceResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := trustedDevice.Metadata.Name
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportGithubConnectorType is the resource metadata type
type resourceTeleportGithubConnectorType struct{}
// resourceTeleportGithubConnector is the resource
type resourceTeleportGithubConnector struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportGithubConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaGithubConnectorV3(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportGithubConnectorType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportGithubConnector{
p: *(p.(*Provider)),
}, nil
}
// Create creates the GithubConnector
func (r resourceTeleportGithubConnector) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnector := &apitypes.GithubConnectorV3{}
diags = tfschema.CopyGithubConnectorV3FromTerraform(ctx, plan, githubConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnectorResource := githubConnector
err = githubConnectorResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting GithubConnector defaults", trace.Wrap(err), "github"))
return
}
id := githubConnectorResource.Metadata.Name
_, err = r.p.Client.GetGithubConnector(ctx, id, true)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("GithubConnector exists in Teleport. Either remove it (tctl rm github/%v)"+
" or import it to the existing state (terraform import teleport_github_connector.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("GithubConnector exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
_, err = r.p.Client.CreateGithubConnector(ctx, githubConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating GithubConnector", trace.Wrap(err), "github"))
return
}
// Not really an inferface, just using the same name for easier templating.
var githubConnectorI apitypes.GithubConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
githubConnectorI, err = r.p.Client.GetGithubConnector(ctx, id, true)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(bErr), "github"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading GithubConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "github")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
githubConnectorResource, ok := githubConnectorI.(*apitypes.GithubConnectorV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Errorf("Can not convert %T to GithubConnectorV3", githubConnectorI), "github"))
return
}
githubConnector = githubConnectorResource
diags = tfschema.CopyGithubConnectorV3ToTerraform(ctx, githubConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: githubConnector.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport GithubConnector
func (r resourceTeleportGithubConnector) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnectorI, err := r.p.Client.GetGithubConnector(ctx, id.Value, true)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
githubConnector := githubConnectorI.(*apitypes.GithubConnectorV3)
diags = tfschema.CopyGithubConnectorV3ToTerraform(ctx, githubConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport GithubConnector
func (r resourceTeleportGithubConnector) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnector := &apitypes.GithubConnectorV3{}
diags = tfschema.CopyGithubConnectorV3FromTerraform(ctx, plan, githubConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
githubConnectorResource := githubConnector
if err := githubConnectorResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating GithubConnector", err, "github"))
return
}
name := githubConnectorResource.Metadata.Name
githubConnectorBefore, err := r.p.Client.GetGithubConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", err, "github"))
return
}
_, err = r.p.Client.UpsertGithubConnector(ctx, githubConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating GithubConnector", err, "github"))
return
}
// Not really an inferface, just using the same name for easier templating.
var githubConnectorI apitypes.GithubConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
githubConnectorI, err = r.p.Client.GetGithubConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", err, "github"))
return
}
if githubConnectorBefore.GetMetadata().Revision != githubConnectorI.GetMetadata().Revision || true {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading GithubConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "github")
return
}
}
githubConnectorResource, ok := githubConnectorI.(*apitypes.GithubConnectorV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Errorf("Can not convert %T to GithubConnectorV3", githubConnectorI), "github"))
return
}
diags = tfschema.CopyGithubConnectorV3ToTerraform(ctx, githubConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport GithubConnector
func (r resourceTeleportGithubConnector) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteGithubConnector(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting GithubConnectorV3", trace.Wrap(err), "github"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports GithubConnector state
func (r resourceTeleportGithubConnector) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
githubConnector, err := r.p.Client.GetGithubConnector(ctx, req.ID, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading GithubConnector", trace.Wrap(err), "github"))
return
}
githubConnectorResource := githubConnector.(*apitypes.GithubConnectorV3)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyGithubConnectorV3ToTerraform(ctx, githubConnectorResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := githubConnectorResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,316 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
loginrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/loginrule/v1"
)
// resourceTeleportLoginRuleType is the resource metadata type
type resourceTeleportLoginRuleType struct{}
// resourceTeleportLoginRule is the resource
type resourceTeleportLoginRule struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportLoginRuleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return schemav1.GenSchemaLoginRule(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportLoginRuleType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportLoginRule{
p: *(p.(*Provider)),
}, nil
}
// Create creates the LoginRule
func (r resourceTeleportLoginRule) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRule := &loginrulev1.LoginRule{}
diags = schemav1.CopyLoginRuleFromTerraform(ctx, plan, loginRule)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRuleResource := loginRule
id := loginRuleResource.Metadata.Name
_, err = r.p.Client.GetLoginRule(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("LoginRule exists in Teleport. Either remove it (tctl rm login_rule/%v)"+
" or import it to the existing state (terraform import teleport_login_rule.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("LoginRule exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
_, err = r.p.Client.UpsertLoginRule(ctx, loginRuleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating LoginRule", trace.Wrap(err), "login_rule"))
return
}
var loginRuleI *loginrulev1.LoginRule
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
loginRuleI, err = r.p.Client.GetLoginRule(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(bErr), "login_rule"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading LoginRule (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "login_rule")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
loginRuleResource = loginRuleI
loginRule = loginRuleResource
diags = schemav1.CopyLoginRuleToTerraform(ctx, loginRule, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: loginRule.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport LoginRule
func (r resourceTeleportLoginRule) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRuleI, err := r.p.Client.GetLoginRule(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
loginRule := loginRuleI
diags = schemav1.CopyLoginRuleToTerraform(ctx, loginRule, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport LoginRule
func (r resourceTeleportLoginRule) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRule := &loginrulev1.LoginRule{}
diags = schemav1.CopyLoginRuleFromTerraform(ctx, plan, loginRule)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
loginRuleResource := loginRule
name := loginRuleResource.Metadata.Name
loginRuleBefore, err := r.p.Client.GetLoginRule(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", err, "login_rule"))
return
}
_, err = r.p.Client.UpsertLoginRule(ctx, loginRuleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating LoginRule", err, "login_rule"))
return
}
var loginRuleI *loginrulev1.LoginRule
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
loginRuleI, err = r.p.Client.GetLoginRule(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", err, "login_rule"))
return
}
if loginRuleBefore.GetMetadata().Revision != loginRuleI.GetMetadata().Revision || true {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading LoginRule (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "login_rule")
return
}
}
loginRuleResource = loginRuleI
diags = schemav1.CopyLoginRuleToTerraform(ctx, loginRule, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport LoginRule
func (r resourceTeleportLoginRule) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteLoginRule(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting LoginRule", trace.Wrap(err), "login_rule"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports LoginRule state
func (r resourceTeleportLoginRule) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
loginRule, err := r.p.Client.GetLoginRule(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading LoginRule", trace.Wrap(err), "login_rule"))
return
}
loginRuleResource := loginRule
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = schemav1.CopyLoginRuleToTerraform(ctx, loginRuleResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := loginRule.Metadata.Name
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportOIDCConnectorType is the resource metadata type
type resourceTeleportOIDCConnectorType struct{}
// resourceTeleportOIDCConnector is the resource
type resourceTeleportOIDCConnector struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportOIDCConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaOIDCConnectorV3(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportOIDCConnectorType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportOIDCConnector{
p: *(p.(*Provider)),
}, nil
}
// Create creates the OIDCConnector
func (r resourceTeleportOIDCConnector) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnector := &apitypes.OIDCConnectorV3{}
diags = tfschema.CopyOIDCConnectorV3FromTerraform(ctx, plan, oidcConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnectorResource := oidcConnector
err = oidcConnectorResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting OIDCConnector defaults", trace.Wrap(err), "oidc"))
return
}
id := oidcConnectorResource.Metadata.Name
_, err = r.p.Client.GetOIDCConnector(ctx, id, true)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("OIDCConnector exists in Teleport. Either remove it (tctl rm oidc/%v)"+
" or import it to the existing state (terraform import teleport_oidc_connector.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("OIDCConnector exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
_, err = r.p.Client.CreateOIDCConnector(ctx, oidcConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating OIDCConnector", trace.Wrap(err), "oidc"))
return
}
// Not really an inferface, just using the same name for easier templating.
var oidcConnectorI apitypes.OIDCConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
oidcConnectorI, err = r.p.Client.GetOIDCConnector(ctx, id, true)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(bErr), "oidc"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading OIDCConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "oidc")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
oidcConnectorResource, ok := oidcConnectorI.(*apitypes.OIDCConnectorV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Errorf("Can not convert %T to OIDCConnectorV3", oidcConnectorI), "oidc"))
return
}
oidcConnector = oidcConnectorResource
diags = tfschema.CopyOIDCConnectorV3ToTerraform(ctx, oidcConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: oidcConnector.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport OIDCConnector
func (r resourceTeleportOIDCConnector) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnectorI, err := r.p.Client.GetOIDCConnector(ctx, id.Value, true)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
oidcConnector := oidcConnectorI.(*apitypes.OIDCConnectorV3)
diags = tfschema.CopyOIDCConnectorV3ToTerraform(ctx, oidcConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport OIDCConnector
func (r resourceTeleportOIDCConnector) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnector := &apitypes.OIDCConnectorV3{}
diags = tfschema.CopyOIDCConnectorV3FromTerraform(ctx, plan, oidcConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oidcConnectorResource := oidcConnector
if err := oidcConnectorResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating OIDCConnector", err, "oidc"))
return
}
name := oidcConnectorResource.Metadata.Name
oidcConnectorBefore, err := r.p.Client.GetOIDCConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", err, "oidc"))
return
}
_, err = r.p.Client.UpsertOIDCConnector(ctx, oidcConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating OIDCConnector", err, "oidc"))
return
}
// Not really an inferface, just using the same name for easier templating.
var oidcConnectorI apitypes.OIDCConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
oidcConnectorI, err = r.p.Client.GetOIDCConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", err, "oidc"))
return
}
if oidcConnectorBefore.GetMetadata().Revision != oidcConnectorI.GetMetadata().Revision || true {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading OIDCConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "oidc")
return
}
}
oidcConnectorResource, ok := oidcConnectorI.(*apitypes.OIDCConnectorV3)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Errorf("Can not convert %T to OIDCConnectorV3", oidcConnectorI), "oidc"))
return
}
diags = tfschema.CopyOIDCConnectorV3ToTerraform(ctx, oidcConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport OIDCConnector
func (r resourceTeleportOIDCConnector) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteOIDCConnector(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting OIDCConnectorV3", trace.Wrap(err), "oidc"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports OIDCConnector state
func (r resourceTeleportOIDCConnector) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
oidcConnector, err := r.p.Client.GetOIDCConnector(ctx, req.ID, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OIDCConnector", trace.Wrap(err), "oidc"))
return
}
oidcConnectorResource := oidcConnector.(*apitypes.OIDCConnectorV3)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyOIDCConnectorV3ToTerraform(ctx, oidcConnectorResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := oidcConnectorResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportOktaImportRuleType is the resource metadata type
type resourceTeleportOktaImportRuleType struct{}
// resourceTeleportOktaImportRule is the resource
type resourceTeleportOktaImportRule struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportOktaImportRuleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaOktaImportRuleV1(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportOktaImportRuleType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportOktaImportRule{
p: *(p.(*Provider)),
}, nil
}
// Create creates the OktaImportRule
func (r resourceTeleportOktaImportRule) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRule := &apitypes.OktaImportRuleV1{}
diags = tfschema.CopyOktaImportRuleV1FromTerraform(ctx, plan, oktaImportRule)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRuleResource := oktaImportRule
err = oktaImportRuleResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting OktaImportRule defaults", trace.Wrap(err), "okta_import_rule"))
return
}
id := oktaImportRuleResource.Metadata.Name
_, err = r.p.Client.OktaClient().GetOktaImportRule(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("OktaImportRule exists in Teleport. Either remove it (tctl rm okta_import_rule/%v)"+
" or import it to the existing state (terraform import teleport_okta_import_rule.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("OktaImportRule exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
_, err = r.p.Client.OktaClient().CreateOktaImportRule(ctx, oktaImportRuleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
// Not really an inferface, just using the same name for easier templating.
var oktaImportRuleI apitypes.OktaImportRule
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
oktaImportRuleI, err = r.p.Client.OktaClient().GetOktaImportRule(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(bErr), "okta_import_rule"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading OktaImportRule (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "okta_import_rule")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
oktaImportRuleResource, ok := oktaImportRuleI.(*apitypes.OktaImportRuleV1)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Errorf("Can not convert %T to OktaImportRuleV1", oktaImportRuleI), "okta_import_rule"))
return
}
oktaImportRule = oktaImportRuleResource
diags = tfschema.CopyOktaImportRuleV1ToTerraform(ctx, oktaImportRule, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: oktaImportRule.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport OktaImportRule
func (r resourceTeleportOktaImportRule) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRuleI, err := r.p.Client.OktaClient().GetOktaImportRule(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
oktaImportRule := oktaImportRuleI.(*apitypes.OktaImportRuleV1)
diags = tfschema.CopyOktaImportRuleV1ToTerraform(ctx, oktaImportRule, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport OktaImportRule
func (r resourceTeleportOktaImportRule) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRule := &apitypes.OktaImportRuleV1{}
diags = tfschema.CopyOktaImportRuleV1FromTerraform(ctx, plan, oktaImportRule)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
oktaImportRuleResource := oktaImportRule
if err := oktaImportRuleResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating OktaImportRule", err, "okta_import_rule"))
return
}
name := oktaImportRuleResource.Metadata.Name
oktaImportRuleBefore, err := r.p.Client.OktaClient().GetOktaImportRule(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", err, "okta_import_rule"))
return
}
_, err = r.p.Client.OktaClient().UpdateOktaImportRule(ctx, oktaImportRuleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating OktaImportRule", err, "okta_import_rule"))
return
}
// Not really an inferface, just using the same name for easier templating.
var oktaImportRuleI apitypes.OktaImportRule
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
oktaImportRuleI, err = r.p.Client.OktaClient().GetOktaImportRule(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", err, "okta_import_rule"))
return
}
if oktaImportRuleBefore.GetMetadata().Revision != oktaImportRuleI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading OktaImportRule (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "okta_import_rule")
return
}
}
oktaImportRuleResource, ok := oktaImportRuleI.(*apitypes.OktaImportRuleV1)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Errorf("Can not convert %T to OktaImportRuleV1", oktaImportRuleI), "okta_import_rule"))
return
}
diags = tfschema.CopyOktaImportRuleV1ToTerraform(ctx, oktaImportRule, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport OktaImportRule
func (r resourceTeleportOktaImportRule) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.OktaClient().DeleteOktaImportRule(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting OktaImportRuleV1", trace.Wrap(err), "okta_import_rule"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports OktaImportRule state
func (r resourceTeleportOktaImportRule) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
oktaImportRule, err := r.p.Client.OktaClient().GetOktaImportRule(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading OktaImportRule", trace.Wrap(err), "okta_import_rule"))
return
}
oktaImportRuleResource := oktaImportRule.(*apitypes.OktaImportRuleV1)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyOktaImportRuleV1ToTerraform(ctx, oktaImportRuleResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := oktaImportRuleResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,347 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"strconv"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportProvisionTokenType is the resource metadata type
type resourceTeleportProvisionTokenType struct{}
// resourceTeleportProvisionToken is the resource
type resourceTeleportProvisionToken struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportProvisionTokenType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaProvisionTokenV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportProvisionTokenType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportProvisionToken{
p: *(p.(*Provider)),
}, nil
}
// Create creates the ProvisionToken
func (r resourceTeleportProvisionToken) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
provisionToken := &apitypes.ProvisionTokenV2{}
diags = tfschema.CopyProvisionTokenV2FromTerraform(ctx, plan, provisionToken)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
if provisionToken.Metadata.Name == "" {
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
resp.Diagnostics.AddError("Failed to generate random token", err.Error())
return
}
provisionToken.Metadata.Name = hex.EncodeToString(b)
}
provisionTokenResource := provisionToken
err = provisionTokenResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting ProvisionToken defaults", trace.Wrap(err), "token"))
return
}
id := provisionTokenResource.Metadata.Name
_, err = r.p.Client.GetToken(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("ProvisionToken exists in Teleport. Either remove it (tctl rm token/%v)"+
" or import it to the existing state (terraform import teleport_provision_token.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("ProvisionToken exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
err = r.p.Client.UpsertToken(ctx, provisionTokenResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating ProvisionToken", trace.Wrap(err), "token"))
return
}
// Not really an inferface, just using the same name for easier templating.
var provisionTokenI apitypes.ProvisionToken
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
provisionTokenI, err = r.p.Client.GetToken(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(bErr), "token"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ProvisionToken (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "token")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
provisionTokenResource, ok := provisionTokenI.(*apitypes.ProvisionTokenV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Errorf("Can not convert %T to ProvisionTokenV2", provisionTokenI), "token"))
return
}
provisionToken = provisionTokenResource
diags = tfschema.CopyProvisionTokenV2ToTerraform(ctx, provisionToken, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: strconv.FormatInt(provisionToken.Metadata.ID, 10)}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport ProvisionToken
func (r resourceTeleportProvisionToken) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
provisionTokenI, err := r.p.Client.GetToken(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
provisionToken := provisionTokenI.(*apitypes.ProvisionTokenV2)
diags = tfschema.CopyProvisionTokenV2ToTerraform(ctx, provisionToken, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport ProvisionToken
func (r resourceTeleportProvisionToken) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
provisionToken := &apitypes.ProvisionTokenV2{}
diags = tfschema.CopyProvisionTokenV2FromTerraform(ctx, plan, provisionToken)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
provisionTokenResource := provisionToken
if err := provisionTokenResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ProvisionToken", err, "token"))
return
}
name := provisionTokenResource.Metadata.Name
provisionTokenBefore, err := r.p.Client.GetToken(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", err, "token"))
return
}
err = r.p.Client.UpsertToken(ctx, provisionTokenResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating ProvisionToken", err, "token"))
return
}
// Not really an inferface, just using the same name for easier templating.
var provisionTokenI apitypes.ProvisionToken
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
provisionTokenI, err = r.p.Client.GetToken(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", err, "token"))
return
}
if provisionTokenBefore.GetMetadata().Revision != provisionTokenI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading ProvisionToken (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "token")
return
}
}
provisionTokenResource, ok := provisionTokenI.(*apitypes.ProvisionTokenV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Errorf("Can not convert %T to ProvisionTokenV2", provisionTokenI), "token"))
return
}
diags = tfschema.CopyProvisionTokenV2ToTerraform(ctx, provisionToken, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport ProvisionToken
func (r resourceTeleportProvisionToken) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteToken(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting ProvisionTokenV2", trace.Wrap(err), "token"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports ProvisionToken state
func (r resourceTeleportProvisionToken) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
provisionToken, err := r.p.Client.GetToken(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading ProvisionToken", trace.Wrap(err), "token"))
return
}
provisionTokenResource := provisionToken.(*apitypes.ProvisionTokenV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyProvisionTokenV2ToTerraform(ctx, provisionTokenResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := provisionTokenResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+335
View File
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportRoleType is the resource metadata type
type resourceTeleportRoleType struct{}
// resourceTeleportRole is the resource
type resourceTeleportRole struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportRoleType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaRoleV6(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportRoleType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportRole{
p: *(p.(*Provider)),
}, nil
}
// Create creates the Role
func (r resourceTeleportRole) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
role := &apitypes.RoleV6{}
diags = tfschema.CopyRoleV6FromTerraform(ctx, plan, role)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
roleResource := role
err = roleResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting Role defaults", trace.Wrap(err), "role"))
return
}
id := roleResource.Metadata.Name
_, err = r.p.Client.GetRole(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("Role exists in Teleport. Either remove it (tctl rm role/%v)"+
" or import it to the existing state (terraform import teleport_role.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("Role exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
_, err = r.p.Client.CreateRole(ctx, roleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating Role", trace.Wrap(err), "role"))
return
}
// Not really an inferface, just using the same name for easier templating.
var roleI apitypes.Role
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
roleI, err = r.p.Client.GetRole(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(bErr), "role"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Role (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "role")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
roleResource, ok := roleI.(*apitypes.RoleV6)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Errorf("Can not convert %T to RoleV6", roleI), "role"))
return
}
role = roleResource
diags = tfschema.CopyRoleV6ToTerraform(ctx, role, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: role.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport Role
func (r resourceTeleportRole) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
roleI, err := r.p.Client.GetRole(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
role := roleI.(*apitypes.RoleV6)
diags = tfschema.CopyRoleV6ToTerraform(ctx, role, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport Role
func (r resourceTeleportRole) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
role := &apitypes.RoleV6{}
diags = tfschema.CopyRoleV6FromTerraform(ctx, plan, role)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
roleResource := role
if err := roleResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Role", err, "role"))
return
}
name := roleResource.Metadata.Name
roleBefore, err := r.p.Client.GetRole(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", err, "role"))
return
}
_, err = r.p.Client.UpsertRole(ctx, roleResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Role", err, "role"))
return
}
// Not really an inferface, just using the same name for easier templating.
var roleI apitypes.Role
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
roleI, err = r.p.Client.GetRole(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", err, "role"))
return
}
if roleBefore.GetMetadata().Revision != roleI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Role (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "role")
return
}
}
roleResource, ok := roleI.(*apitypes.RoleV6)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Errorf("Can not convert %T to RoleV6", roleI), "role"))
return
}
diags = tfschema.CopyRoleV6ToTerraform(ctx, role, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport Role
func (r resourceTeleportRole) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteRole(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting RoleV6", trace.Wrap(err), "role"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports Role state
func (r resourceTeleportRole) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
role, err := r.p.Client.GetRole(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Role", trace.Wrap(err), "role"))
return
}
roleResource := role.(*apitypes.RoleV6)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyRoleV6ToTerraform(ctx, roleResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := roleResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportSAMLConnectorType is the resource metadata type
type resourceTeleportSAMLConnectorType struct{}
// resourceTeleportSAMLConnector is the resource
type resourceTeleportSAMLConnector struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportSAMLConnectorType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaSAMLConnectorV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportSAMLConnectorType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportSAMLConnector{
p: *(p.(*Provider)),
}, nil
}
// Create creates the SAMLConnector
func (r resourceTeleportSAMLConnector) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnector := &apitypes.SAMLConnectorV2{}
diags = tfschema.CopySAMLConnectorV2FromTerraform(ctx, plan, samlConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnectorResource := samlConnector
err = samlConnectorResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting SAMLConnector defaults", trace.Wrap(err), "saml"))
return
}
id := samlConnectorResource.Metadata.Name
_, err = r.p.Client.GetSAMLConnector(ctx, id, true)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("SAMLConnector exists in Teleport. Either remove it (tctl rm saml/%v)"+
" or import it to the existing state (terraform import teleport_saml_connector.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("SAMLConnector exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
_, err = r.p.Client.CreateSAMLConnector(ctx, samlConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating SAMLConnector", trace.Wrap(err), "saml"))
return
}
// Not really an inferface, just using the same name for easier templating.
var samlConnectorI apitypes.SAMLConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
samlConnectorI, err = r.p.Client.GetSAMLConnector(ctx, id, true)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(bErr), "saml"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading SAMLConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "saml")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
samlConnectorResource, ok := samlConnectorI.(*apitypes.SAMLConnectorV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Errorf("Can not convert %T to SAMLConnectorV2", samlConnectorI), "saml"))
return
}
samlConnector = samlConnectorResource
diags = tfschema.CopySAMLConnectorV2ToTerraform(ctx, samlConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: samlConnector.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport SAMLConnector
func (r resourceTeleportSAMLConnector) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnectorI, err := r.p.Client.GetSAMLConnector(ctx, id.Value, true)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
samlConnector := samlConnectorI.(*apitypes.SAMLConnectorV2)
diags = tfschema.CopySAMLConnectorV2ToTerraform(ctx, samlConnector, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport SAMLConnector
func (r resourceTeleportSAMLConnector) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnector := &apitypes.SAMLConnectorV2{}
diags = tfschema.CopySAMLConnectorV2FromTerraform(ctx, plan, samlConnector)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
samlConnectorResource := samlConnector
if err := samlConnectorResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating SAMLConnector", err, "saml"))
return
}
name := samlConnectorResource.Metadata.Name
samlConnectorBefore, err := r.p.Client.GetSAMLConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", err, "saml"))
return
}
_, err = r.p.Client.UpsertSAMLConnector(ctx, samlConnectorResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating SAMLConnector", err, "saml"))
return
}
// Not really an inferface, just using the same name for easier templating.
var samlConnectorI apitypes.SAMLConnector
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
samlConnectorI, err = r.p.Client.GetSAMLConnector(ctx, name, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", err, "saml"))
return
}
if samlConnectorBefore.GetMetadata().Revision != samlConnectorI.GetMetadata().Revision || true {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading SAMLConnector (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "saml")
return
}
}
samlConnectorResource, ok := samlConnectorI.(*apitypes.SAMLConnectorV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Errorf("Can not convert %T to SAMLConnectorV2", samlConnectorI), "saml"))
return
}
diags = tfschema.CopySAMLConnectorV2ToTerraform(ctx, samlConnector, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport SAMLConnector
func (r resourceTeleportSAMLConnector) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteSAMLConnector(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting SAMLConnectorV2", trace.Wrap(err), "saml"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports SAMLConnector state
func (r resourceTeleportSAMLConnector) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
samlConnector, err := r.p.Client.GetSAMLConnector(ctx, req.ID, true)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SAMLConnector", trace.Wrap(err), "saml"))
return
}
samlConnectorResource := samlConnector.(*apitypes.SAMLConnectorV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopySAMLConnectorV2ToTerraform(ctx, samlConnectorResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := samlConnectorResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+337
View File
@@ -0,0 +1,337 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportServerType is the resource metadata type
type resourceTeleportServerType struct{}
// resourceTeleportServer is the resource
type resourceTeleportServer struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportServerType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaServerV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportServerType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportServer{
p: *(p.(*Provider)),
}, nil
}
// Create creates the Server
func (r resourceTeleportServer) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
server := &apitypes.ServerV2{}
diags = tfschema.CopyServerV2FromTerraform(ctx, plan, server)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
serverResource := server
serverResource.Kind = apitypes.KindNode
err = serverResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting Server defaults", trace.Wrap(err), "node"))
return
}
id := serverResource.Metadata.Name
_, err = r.p.Client.GetNode(ctx, defaults.Namespace, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("Server exists in Teleport. Either remove it (tctl rm node/%v)"+
" or import it to the existing state (terraform import teleport_server.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("Server exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
_, err = r.p.Client.UpsertNode(ctx, serverResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating Server", trace.Wrap(err), "node"))
return
}
// Not really an inferface, just using the same name for easier templating.
var serverI apitypes.Server
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
serverI, err = r.p.Client.GetNode(ctx, defaults.Namespace, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(bErr), "node"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Server (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "node")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
serverResource, ok := serverI.(*apitypes.ServerV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Errorf("Can not convert %T to ServerV2", serverI), "node"))
return
}
server = serverResource
diags = tfschema.CopyServerV2ToTerraform(ctx, server, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: server.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport Server
func (r resourceTeleportServer) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
serverI, err := r.p.Client.GetNode(ctx, defaults.Namespace, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
server := serverI.(*apitypes.ServerV2)
diags = tfschema.CopyServerV2ToTerraform(ctx, server, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport Server
func (r resourceTeleportServer) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
server := &apitypes.ServerV2{}
diags = tfschema.CopyServerV2FromTerraform(ctx, plan, server)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
serverResource := server
if err := serverResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Server", err, "node"))
return
}
name := serverResource.Metadata.Name
serverBefore, err := r.p.Client.GetNode(ctx, defaults.Namespace, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", err, "node"))
return
}
_, err = r.p.Client.UpsertNode(ctx, serverResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating Server", err, "node"))
return
}
// Not really an inferface, just using the same name for easier templating.
var serverI apitypes.Server
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
serverI, err = r.p.Client.GetNode(ctx, defaults.Namespace, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", err, "node"))
return
}
if serverBefore.GetMetadata().Revision != serverI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading Server (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "node")
return
}
}
serverResource, ok := serverI.(*apitypes.ServerV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Errorf("Can not convert %T to ServerV2", serverI), "node"))
return
}
diags = tfschema.CopyServerV2ToTerraform(ctx, server, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport Server
func (r resourceTeleportServer) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteNode(ctx, defaults.Namespace, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting ServerV2", trace.Wrap(err), "node"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports Server state
func (r resourceTeleportServer) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
server, err := r.p.Client.GetNode(ctx, defaults.Namespace, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading Server", trace.Wrap(err), "node"))
return
}
serverResource := server.(*apitypes.ServerV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyServerV2ToTerraform(ctx, serverResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := serverResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,300 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportSessionRecordingConfigType is the resource metadata type
type resourceTeleportSessionRecordingConfigType struct{}
// resourceTeleportSessionRecordingConfig is the resource
type resourceTeleportSessionRecordingConfig struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportSessionRecordingConfigType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaSessionRecordingConfigV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportSessionRecordingConfigType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportSessionRecordingConfig{
p: *(p.(*Provider)),
}, nil
}
// Create creates the SessionRecordingConfig
func (r resourceTeleportSessionRecordingConfig) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
sessionRecordingConfig := &apitypes.SessionRecordingConfigV2{}
diags = tfschema.CopySessionRecordingConfigV2FromTerraform(ctx, plan, sessionRecordingConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := sessionRecordingConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting SessionRecordingConfig defaults", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfigBefore, err := r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil && !trace.IsNotFound(err) {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
err = r.p.Client.SetSessionRecordingConfig(ctx, sessionRecordingConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
var sessionRecordingConfigI apitypes.SessionRecordingConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
sessionRecordingConfigI, err = r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
if sessionRecordingConfigBefore.GetMetadata().Revision != sessionRecordingConfigI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(bErr), "session_recording_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading SessionRecordingConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "session_recording_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfig, ok := sessionRecordingConfigI.(*apitypes.SessionRecordingConfigV2)
if !ok {
resp.Diagnostics.Append(
diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Errorf("Can not convert %T to SessionRecordingConfigV2", sessionRecordingConfigI), "session_recording_config"),
)
return
}
diags = tfschema.CopySessionRecordingConfigV2ToTerraform(ctx, sessionRecordingConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: "session_recording_config"}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport SessionRecordingConfig
func (r resourceTeleportSessionRecordingConfig) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
sessionRecordingConfigI, err := r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfig := sessionRecordingConfigI.(*apitypes.SessionRecordingConfigV2)
diags = tfschema.CopySessionRecordingConfigV2ToTerraform(ctx, sessionRecordingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport SessionRecordingConfig
func (r resourceTeleportSessionRecordingConfig) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
sessionRecordingConfig := &apitypes.SessionRecordingConfigV2{}
diags = tfschema.CopySessionRecordingConfigV2FromTerraform(ctx, plan, sessionRecordingConfig)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := sessionRecordingConfig.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfigBefore, err := r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
err = r.p.Client.SetSessionRecordingConfig(ctx, sessionRecordingConfig)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
var sessionRecordingConfigI apitypes.SessionRecordingConfig
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
sessionRecordingConfigI, err = r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
if sessionRecordingConfigBefore.GetMetadata().Revision != sessionRecordingConfigI.GetMetadata().Revision || false {
break
}
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(bErr), "session_recording_config"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading SessionRecordingConfig (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "session_recording_config")
return
}
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfig = sessionRecordingConfigI.(*apitypes.SessionRecordingConfigV2)
diags = tfschema.CopySessionRecordingConfigV2ToTerraform(ctx, sessionRecordingConfig, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport SessionRecordingConfig
func (r resourceTeleportSessionRecordingConfig) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
err := r.p.Client.ResetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports SessionRecordingConfig state
func (r resourceTeleportSessionRecordingConfig) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
sessionRecordingConfigI, err := r.p.Client.GetSessionRecordingConfig(ctx)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating SessionRecordingConfig", trace.Wrap(err), "session_recording_config"))
return
}
sessionRecordingConfig := sessionRecordingConfigI.(*apitypes.SessionRecordingConfigV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopySessionRecordingConfigV2ToTerraform(ctx, sessionRecordingConfig, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
state.Attrs["id"] = types.String{Value: sessionRecordingConfig.Metadata.Name}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportTrustedClusterType is the resource metadata type
type resourceTeleportTrustedClusterType struct{}
// resourceTeleportTrustedCluster is the resource
type resourceTeleportTrustedCluster struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportTrustedClusterType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaTrustedClusterV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportTrustedClusterType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportTrustedCluster{
p: *(p.(*Provider)),
}, nil
}
// Create creates the TrustedCluster
func (r resourceTeleportTrustedCluster) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedCluster := &apitypes.TrustedClusterV2{}
diags = tfschema.CopyTrustedClusterV2FromTerraform(ctx, plan, trustedCluster)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedClusterResource := trustedCluster
err = trustedClusterResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting TrustedCluster defaults", trace.Wrap(err), "trusted_cluster"))
return
}
id := trustedClusterResource.Metadata.Name
_, err = r.p.Client.GetTrustedCluster(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("TrustedCluster exists in Teleport. Either remove it (tctl rm trusted_cluster/%v)"+
" or import it to the existing state (terraform import teleport_trusted_cluster.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("TrustedCluster exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
_, err = r.p.Client.UpsertTrustedCluster(ctx, trustedClusterResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
// Not really an inferface, just using the same name for easier templating.
var trustedClusterI apitypes.TrustedCluster
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
trustedClusterI, err = r.p.Client.GetTrustedCluster(ctx, id)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(bErr), "trusted_cluster"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading TrustedCluster (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "trusted_cluster")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
trustedClusterResource, ok := trustedClusterI.(*apitypes.TrustedClusterV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Errorf("Can not convert %T to TrustedClusterV2", trustedClusterI), "trusted_cluster"))
return
}
trustedCluster = trustedClusterResource
diags = tfschema.CopyTrustedClusterV2ToTerraform(ctx, trustedCluster, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: trustedCluster.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport TrustedCluster
func (r resourceTeleportTrustedCluster) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedClusterI, err := r.p.Client.GetTrustedCluster(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
trustedCluster := trustedClusterI.(*apitypes.TrustedClusterV2)
diags = tfschema.CopyTrustedClusterV2ToTerraform(ctx, trustedCluster, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport TrustedCluster
func (r resourceTeleportTrustedCluster) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedCluster := &apitypes.TrustedClusterV2{}
diags = tfschema.CopyTrustedClusterV2FromTerraform(ctx, plan, trustedCluster)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
trustedClusterResource := trustedCluster
if err := trustedClusterResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating TrustedCluster", err, "trusted_cluster"))
return
}
name := trustedClusterResource.Metadata.Name
trustedClusterBefore, err := r.p.Client.GetTrustedCluster(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", err, "trusted_cluster"))
return
}
_, err = r.p.Client.UpsertTrustedCluster(ctx, trustedClusterResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating TrustedCluster", err, "trusted_cluster"))
return
}
// Not really an inferface, just using the same name for easier templating.
var trustedClusterI apitypes.TrustedCluster
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
trustedClusterI, err = r.p.Client.GetTrustedCluster(ctx, name)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", err, "trusted_cluster"))
return
}
if trustedClusterBefore.GetMetadata().Revision != trustedClusterI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading TrustedCluster (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "trusted_cluster")
return
}
}
trustedClusterResource, ok := trustedClusterI.(*apitypes.TrustedClusterV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Errorf("Can not convert %T to TrustedClusterV2", trustedClusterI), "trusted_cluster"))
return
}
diags = tfschema.CopyTrustedClusterV2ToTerraform(ctx, trustedCluster, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport TrustedCluster
func (r resourceTeleportTrustedCluster) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteTrustedCluster(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting TrustedClusterV2", trace.Wrap(err), "trusted_cluster"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports TrustedCluster state
func (r resourceTeleportTrustedCluster) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
trustedCluster, err := r.p.Client.GetTrustedCluster(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading TrustedCluster", trace.Wrap(err), "trusted_cluster"))
return
}
trustedClusterResource := trustedCluster.(*apitypes.TrustedClusterV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyTrustedClusterV2ToTerraform(ctx, trustedClusterResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := trustedClusterResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+335
View File
@@ -0,0 +1,335 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// resourceTeleportUserType is the resource metadata type
type resourceTeleportUserType struct{}
// resourceTeleportUser is the resource
type resourceTeleportUser struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportUserType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaUserV2(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportUserType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportUser{
p: *(p.(*Provider)),
}, nil
}
// Create creates the User
func (r resourceTeleportUser) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var err error
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
user := &apitypes.UserV2{}
diags = tfschema.CopyUserV2FromTerraform(ctx, plan, user)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
userResource := user
err = userResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error setting User defaults", trace.Wrap(err), "user"))
return
}
id := userResource.Metadata.Name
_, err = r.p.Client.GetUser(ctx, id, false)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("User exists in Teleport. Either remove it (tctl rm user/%v)"+
" or import it to the existing state (terraform import teleport_user.%v %v)", id, id, id)
resp.Diagnostics.Append(diagFromErr("User exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
_, err = r.p.Client.CreateUser(ctx, userResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error creating User", trace.Wrap(err), "user"))
return
}
// Not really an inferface, just using the same name for easier templating.
var userI apitypes.User
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
userI, err = r.p.Client.GetUser(ctx, id, false)
if trace.IsNotFound(err) {
if bErr := backoff.Do(ctx); bErr != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(bErr), "user"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading User (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "user")
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
userResource, ok := userI.(*apitypes.UserV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Errorf("Can not convert %T to UserV2", userI), "user"))
return
}
user = userResource
diags = tfschema.CopyUserV2ToTerraform(ctx, user, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: user.Metadata.Name}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport User
func (r resourceTeleportUser) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state types.Object
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var id types.String
diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
userI, err := r.p.Client.GetUser(ctx, id.Value, false)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
user := userI.(*apitypes.UserV2)
diags = tfschema.CopyUserV2ToTerraform(ctx, user, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Update updates teleport User
func (r resourceTeleportUser) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
if !r.p.IsConfigured(resp.Diagnostics) {
return
}
var plan types.Object
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
user := &apitypes.UserV2{}
diags = tfschema.CopyUserV2FromTerraform(ctx, plan, user)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
userResource := user
if err := userResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating User", err, "user"))
return
}
name := userResource.Metadata.Name
userBefore, err := r.p.Client.GetUser(ctx, name, false)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", err, "user"))
return
}
_, err = r.p.Client.UpsertUser(ctx, userResource)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error updating User", err, "user"))
return
}
// Not really an inferface, just using the same name for easier templating.
var userI apitypes.User
tries := 0
backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock())
for {
tries = tries + 1
userI, err = r.p.Client.GetUser(ctx, name, false)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", err, "user"))
return
}
if userBefore.GetMetadata().Revision != userI.GetMetadata().Revision || false {
break
}
if err := backoff.Do(ctx); err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
if tries >= r.p.RetryConfig.MaxTries {
diagMessage := fmt.Sprintf("Error reading User (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "user")
return
}
}
userResource, ok := userI.(*apitypes.UserV2)
if !ok {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Errorf("Can not convert %T to UserV2", userI), "user"))
return
}
diags = tfschema.CopyUserV2ToTerraform(ctx, user, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Delete deletes Teleport User
func (r resourceTeleportUser) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var id types.String
diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.p.Client.DeleteUser(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error deleting UserV2", trace.Wrap(err), "user"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports User state
func (r resourceTeleportUser) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
user, err := r.p.Client.GetUser(ctx, req.ID, false)
if err != nil {
resp.Diagnostics.Append(diagFromWrappedErr("Error reading User", trace.Wrap(err), "user"))
return
}
userResource := user.(*apitypes.UserV2)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyUserV2ToTerraform(ctx, userResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := userResource.GetName()
state.Attrs["id"] = types.String{Value: id}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
+2670
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,123 @@
/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"github.com/gravitational/teleport/api/client"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
type nextAuditDateComparer struct {
client *client.Client
nextAuditDate time.Time
}
func (c *nextAuditDateComparer) CaptureNextAuditDate(name string) resource.TestCheckFunc {
return func(state *terraform.State) error {
al, err := c.client.AccessListClient().GetAccessList(context.TODO(), name)
if err != nil {
return trace.Wrap(err)
}
c.nextAuditDate = al.Spec.Audit.NextAuditDate
return nil
}
}
func (c *nextAuditDateComparer) TestNextAuditDateUnchanged(name string) resource.TestCheckFunc {
return func(state *terraform.State) error {
al, err := c.client.AccessListClient().GetAccessList(context.TODO(), name)
if err != nil {
return trace.Wrap(err)
}
diff := cmp.Diff(c.nextAuditDate, al.Spec.Audit.NextAuditDate, cmpopts.EquateApproxTime(2*time.Millisecond))
if diff != "" {
return trace.CompareFailed("NextAuditDate should not have changed, was %s, is now %s", c.nextAuditDate, al.Spec.Audit.NextAuditDate)
}
return nil
}
}
func (s *TerraformSuite) TestAccessList() {
if !s.teleportFeatures.GetAdvancedAccessWorkflows() {
s.T().Skip("Doesn't work in OSS version, requires AdvancedWorkflow")
}
checkAccessListDestroyed := func(state *terraform.State) error {
_, err := s.client.AccessListClient().GetAccessList(context.TODO(), "test")
if trace.IsNotFound(err) {
return nil
}
return err
}
name := "teleport_access_list.test"
auditDateChecker := nextAuditDateComparer{client: s.client}
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkAccessListDestroyed,
Steps: []resource.TestStep{
{
Config: s.getFixture("access_list_0_create.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "header.metadata.name", "test"),
resource.TestCheckResourceAttr(name, "spec.description", "test description"),
resource.TestCheckResourceAttr(name, "spec.owners.0.name", "gru"),
resource.TestCheckResourceAttr(name, "spec.membership_requires.roles.0", "minion"),
resource.TestCheckResourceAttr(name, "spec.grants.roles.0", "crane-operator"),
resource.TestCheckResourceAttr(name, "spec.audit.recurrence.frequency", "3"),
auditDateChecker.CaptureNextAuditDate("test"),
),
},
{
Config: s.getFixture("access_list_0_create.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("access_list_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "spec.grants.traits.0.key", "allowed-machines"),
resource.TestCheckResourceAttr(name, "spec.grants.traits.0.values.0", "crane"),
resource.TestCheckResourceAttr(name, "spec.grants.traits.0.values.1", "forklift"),
auditDateChecker.TestNextAuditDateUnchanged("test"),
),
},
{
Config: s.getFixture("access_list_1_update.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("access_list_2_expiring.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "header.metadata.expires", "2038-01-01T00:00:00Z"),
auditDateChecker.TestNextAuditDateUnchanged("test"),
),
},
{
Config: s.getFixture("access_list_2_expiring.tf"),
PlanOnly: true,
},
},
})
}
+159
View File
@@ -0,0 +1,159 @@
/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"time"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
)
func (s *TerraformSuite) TestApp() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
checkDestroyed := func(state *terraform.State) error {
_, err := s.client.GetApp(ctx, "test")
if trace.IsNotFound(err) {
return nil
}
return err
}
name := "teleport_app.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkDestroyed,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("app_0_create.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
{
Config: s.getFixture("app_0_create.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("app_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
{
Config: s.getFixture("app_1_update.tf"),
PlanOnly: true,
},
},
})
}
func (s *TerraformSuite) TestImportApp() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
r := "teleport_app"
id := "test_import"
name := r + "." + id
app := &types.AppV3{
Metadata: types.Metadata{
Name: id,
},
Spec: types.AppSpecV3{
URI: "localhost:3000/test",
},
}
err := app.CheckAndSetDefaults()
require.NoError(s.T(), err)
err = s.client.CreateApp(ctx, app)
require.NoError(s.T(), err)
require.Eventually(s.T(), func() bool {
_, err := s.client.GetApp(ctx, app.GetName())
if trace.IsNotFound(err) {
return false
}
require.NoError(s.T(), err)
return true
}, 5*time.Second, time.Second)
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.terraformConfig + "\n" + `resource "` + r + `" "` + id + `" { }`,
ResourceName: name,
ImportState: true,
ImportStateId: id,
ImportStateCheck: func(state []*terraform.InstanceState) error {
require.Equal(s.T(), state[0].Attributes["kind"], "app")
require.Equal(s.T(), state[0].Attributes["spec.uri"], "localhost:3000/test")
return nil
},
},
},
})
}
func (s *TerraformSuiteWithCache) TestAppWithCache() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
checkDestroyed := func(state *terraform.State) error {
_, err := s.client.GetApp(ctx, "test")
if trace.IsNotFound(err) {
return nil
}
return err
}
name := "teleport_app.test_with_cache"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkDestroyed,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("app_0_create_with_cache.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
{
Config: s.getFixture("app_0_create_with_cache.tf"),
PlanOnly: true,
},
},
})
}
@@ -0,0 +1,148 @@
/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"time"
"github.com/gravitational/teleport/api/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
)
func (s *TerraformSuite) TestAuthPreference() {
name := "teleport_auth_preference.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
PreventPostDestroyRefresh: true,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("auth_preference_0_set.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_auth_preference"),
resource.TestCheckResourceAttr(name, "metadata.labels.example", "yes"),
resource.TestCheckResourceAttr(name, "spec.disconnect_expired_cert", "true"),
),
},
{
Config: s.getFixture("auth_preference_0_set.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("auth_preference_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_auth_preference"),
resource.TestCheckResourceAttr(name, "spec.disconnect_expired_cert", "false"),
),
},
{
Config: s.getFixture("auth_preference_1_update.tf"),
PlanOnly: true,
},
},
})
}
func (s *TerraformSuite) TestImportAuthPreference() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
r := "teleport_auth_preference"
id := "test_import"
name := r + "." + id
authPreference := &types.AuthPreferenceV2{
Metadata: types.Metadata{},
Spec: types.AuthPreferenceSpecV2{
DisconnectExpiredCert: types.NewBoolOption(true),
},
}
err := authPreference.CheckAndSetDefaults()
require.NoError(s.T(), err)
authPreferencesBefore, err := s.client.GetAuthPreference(ctx)
require.NoError(s.T(), err)
err = s.client.SetAuthPreference(ctx, authPreference)
require.NoError(s.T(), err)
require.Eventually(s.T(), func() bool {
authPreferencesCurrent, err := s.client.GetAuthPreference(ctx)
require.NoError(s.T(), err)
return authPreferencesBefore.GetMetadata().ID != authPreferencesCurrent.GetMetadata().ID
}, 5*time.Second, time.Second)
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.terraformConfig + "\n" + `resource "` + r + `" "` + id + `" { }`,
ResourceName: name,
ImportState: true,
ImportStateId: id,
ImportStateCheck: func(state []*terraform.InstanceState) error {
require.Equal(s.T(), state[0].Attributes["kind"], "cluster_auth_preference")
require.Equal(s.T(), state[0].Attributes["spec.disconnect_expired_cert"], "true")
return nil
},
},
},
})
}
func (s *TerraformSuiteWithCache) TestAuthPreferenceAddLabel() {
name := "teleport_auth_preference.cluster_auth_preference"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
PreventPostDestroyRefresh: true,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("auth_preference_0_cluster.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_auth_preference"),
resource.TestCheckNoResourceAttr(name, "metadata.labels"),
resource.TestCheckResourceAttr(name, "spec.type", "oidc"),
),
},
{
Config: s.getFixture("auth_preference_0_cluster.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("auth_preference_1_cluster.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_auth_preference"),
resource.TestCheckResourceAttr(name, "metadata.labels.provisioner", "terraform"),
resource.TestCheckResourceAttr(name, "spec.type", "oidc"),
),
},
{
Config: s.getFixture("auth_preference_1_cluster.tf"),
PlanOnly: true,
},
},
})
}
+97
View File
@@ -0,0 +1,97 @@
/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func (s *TerraformSuite) TestBot() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
checkResourcesDestroyed := func(state *terraform.State) error {
var errs []error
if _, err := s.client.GetToken(ctx, "bot-test"); err != nil {
if !trace.IsNotFound(err) {
errs = append(errs, err)
}
}
if _, err := s.client.GetUser(ctx, "bot-test", false); err != nil {
if !trace.IsNotFound(err) {
errs = append(errs, err)
}
}
return trace.NewAggregate(errs...)
}
tokenName := "teleport_provision_token.bot_test"
botName := "teleport_bot.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkResourcesDestroyed,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("bot_0_create.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(tokenName, "kind", "token"),
resource.TestCheckResourceAttr(tokenName, "metadata.name", "bot-test"),
resource.TestCheckResourceAttr(tokenName, "spec.roles.0", "Bot"),
resource.TestCheckResourceAttr(botName, "name", "test"),
resource.TestCheckResourceAttr(botName, "user_name", "bot-test"),
resource.TestCheckResourceAttr(botName, "role_name", "bot-test"),
resource.TestCheckResourceAttr(botName, "token_id", "bot-test"),
resource.TestCheckResourceAttr(botName, "roles.0", "terraform"),
resource.TestCheckNoResourceAttr(botName, "spec.traits.logins1"),
),
},
{
Config: s.getFixture("bot_0_create.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("bot_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(tokenName, "kind", "token"),
resource.TestCheckResourceAttr(tokenName, "metadata.name", "bot-test"),
resource.TestCheckResourceAttr(tokenName, "spec.roles.0", "Bot"),
resource.TestCheckResourceAttr(botName, "name", "test"),
resource.TestCheckResourceAttr(botName, "user_name", "bot-test"),
resource.TestCheckResourceAttr(botName, "role_name", "bot-test"),
resource.TestCheckResourceAttr(botName, "token_id", "bot-test"),
resource.TestCheckResourceAttr(botName, "roles.0", "terraform"),
// Note: traits are immutable and the plan will not converge
// if the resource is not recreated when traits are
// modified.
resource.TestCheckResourceAttr(botName, "traits.logins1.0", "example"),
),
},
{
Config: s.getFixture("bot_1_update.tf"),
PlanOnly: true,
},
},
})
}
@@ -0,0 +1,57 @@
/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)
func (s *TerraformSuite) TestClusterMaintenanceConfig() {
name := "teleport_cluster_maintenance_config.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
PreventPostDestroyRefresh: true,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("maintenance_config_0_set.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_maintenance_config"),
resource.TestCheckResourceAttr(name, "spec.agent_upgrades.utc_start_hour", "1"),
resource.TestCheckResourceAttr(name, "spec.agent_upgrades.weekdays.0", "monday"),
),
},
{
Config: s.getFixture("maintenance_config_0_set.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("maintenance_config_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_maintenance_config"),
resource.TestCheckResourceAttr(name, "spec.agent_upgrades.utc_start_hour", "12"),
resource.TestCheckResourceAttr(name, "spec.agent_upgrades.weekdays.0", "tuesday"),
),
},
{
Config: s.getFixture("maintenance_config_1_update.tf"),
PlanOnly: true,
},
},
})
}
@@ -0,0 +1,113 @@
/*
Copyright 2023 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"time"
"github.com/gravitational/teleport/api/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
)
func (s *TerraformSuite) TestClusterNetworkingConfig() {
name := "teleport_cluster_networking_config.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
PreventPostDestroyRefresh: true,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.getFixture("networking_config_0_set.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_networking_config"),
resource.TestCheckResourceAttr(name, "metadata.labels.example", "yes"),
resource.TestCheckResourceAttr(name, "spec.client_idle_timeout", "30m"),
),
},
{
Config: s.getFixture("networking_config_0_set.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("networking_config_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "cluster_networking_config"),
resource.TestCheckResourceAttr(name, "metadata.labels.example", "no"),
resource.TestCheckResourceAttr(name, "spec.client_idle_timeout", "1h"),
),
},
{
Config: s.getFixture("networking_config_1_update.tf"),
PlanOnly: true,
},
},
})
}
func (s *TerraformSuite) TestImportClusterNetworkingConfig() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
r := "teleport_cluster_networking_config"
id := "test_import"
name := r + "." + id
clusterNetworkingConfig := &types.ClusterNetworkingConfigV2{
Metadata: types.Metadata{},
Spec: types.ClusterNetworkingConfigSpecV2{
ClientIdleTimeout: types.Duration(30 * time.Second),
},
}
err := clusterNetworkingConfig.CheckAndSetDefaults()
require.NoError(s.T(), err)
clusterNetworkConfigBefore, err := s.client.GetClusterNetworkingConfig(ctx)
require.NoError(s.T(), err)
err = s.client.SetClusterNetworkingConfig(ctx, clusterNetworkingConfig)
require.NoError(s.T(), err)
require.Eventually(s.T(), func() bool {
clusterNetworkConfigCurrent, err := s.client.GetClusterNetworkingConfig(ctx)
require.NoError(s.T(), err)
return clusterNetworkConfigBefore.GetMetadata().ID != clusterNetworkConfigCurrent.GetMetadata().ID
}, 5*time.Second, time.Second)
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
IsUnitTest: true,
Steps: []resource.TestStep{
{
Config: s.terraformConfig + "\n" + `resource "` + r + `" "` + id + `" { }`,
ResourceName: name,
ImportState: true,
ImportStateId: id,
ImportStateCheck: func(state []*terraform.InstanceState) error {
require.Equal(s.T(), state[0].Attributes["kind"], "cluster_networking_config")
require.Equal(s.T(), state[0].Attributes["spec.client_idle_timeout"], "30s")
return nil
},
},
},
})
}
@@ -0,0 +1,168 @@
/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"encoding/base64"
"os"
"regexp"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/stretchr/testify/require"
)
func (s *TerraformSuite) getTLSCerts() {
}
func (s *TerraformSuite) TestConfigureAuthBase64() {
name := "teleport_app.test_auth_b64"
key, err := os.ReadFile(s.teleportConfig.ClientKey)
require.NoError(s.T(), err)
keyBase64 := base64.StdEncoding.EncodeToString(key)
cert, err := os.ReadFile(s.teleportConfig.ClientCrt)
require.NoError(s.T(), err)
certBase64 := base64.StdEncoding.EncodeToString(cert)
rootCA, err := os.ReadFile(s.teleportConfig.RootCAs)
require.NoError(s.T(), err)
rootCABase64 := base64.StdEncoding.EncodeToString(rootCA)
providerConfigUsingB64Auth := `
provider "teleport" {
addr = "` + s.teleportConfig.Addr + `"
key_base64 = "` + keyBase64 + `"
cert_base64 = "` + certBase64 + `"
root_ca_base64 = "` + rootCABase64 + `"
}
`
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.getFixtureWithCustomConfig("app_0_create_auth_b64.tf", providerConfigUsingB64Auth),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
},
})
}
func (s *TerraformSuite) TestConfigureAuthFiles() {
name := "teleport_app.test_auth_files"
providerConfigUsingAuthFiles := `
provider "teleport" {
addr = "` + s.teleportConfig.Addr + `"
key_path = "` + s.teleportConfig.ClientKey + `"
cert_path = "` + s.teleportConfig.ClientCrt + `"
root_ca_path = "` + s.teleportConfig.RootCAs + `"
}
`
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.getFixtureWithCustomConfig("app_0_create_auth_files.tf", providerConfigUsingAuthFiles),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
},
})
}
func (s *TerraformSuite) TestConfigureIdentityFilePath() {
name := "teleport_app.test"
providerConfigUsingAuthFiles := `
provider "teleport" {
addr = "` + s.teleportConfig.Addr + `"
identity_file_path = "` + s.teleportConfig.Identity + `"
}
`
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.getFixtureWithCustomConfig("app_0_create.tf", providerConfigUsingAuthFiles),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
},
})
}
func (s *TerraformSuite) TestConfigureIdentityFileBase64() {
name := "teleport_app.test"
identity, err := os.ReadFile(s.teleportConfig.Identity)
require.NoError(s.T(), err)
identityAsB64 := base64.StdEncoding.EncodeToString(identity)
providerConfigUsingAuthFiles := `
provider "teleport" {
addr = "` + s.teleportConfig.Addr + `"
identity_file_base64 = "` + identityAsB64 + `"
}
`
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.getFixtureWithCustomConfig("app_0_create.tf", providerConfigUsingAuthFiles),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "app"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:3000"),
),
},
},
})
}
func (s *TerraformSuite) TestConfigureIdentityFileBase64_InvalidBase64() {
identityAsB64 := base64.StdEncoding.EncodeToString([]byte("invalid"))
providerConfigUsingAuthFiles := `
provider "teleport" {
addr = "` + s.teleportConfig.Addr + `"
identity_file_base64 = "` + identityAsB64 + `"
dial_timeout_duration = "1s"
}
`
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.getFixtureWithCustomConfig("app_0_create.tf", providerConfigUsingAuthFiles),
ExpectError: regexp.MustCompile("identity file could not be decoded"),
},
},
})
}
@@ -0,0 +1,129 @@
/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"time"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
)
func (s *TerraformSuite) TestDatabase() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
checkDestroyed := func(state *terraform.State) error {
_, err := s.client.GetDatabase(ctx, "test")
if trace.IsNotFound(err) {
return nil
}
return err
}
name := "teleport_database.test"
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkDestroyed,
Steps: []resource.TestStep{
{
Config: s.getFixture("database_0_create.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "db"),
resource.TestCheckResourceAttr(name, "metadata.expires", "2032-10-12T07:20:50Z"),
resource.TestCheckResourceAttr(name, "spec.protocol", "postgres"),
resource.TestCheckResourceAttr(name, "spec.uri", "localhost:5432"),
),
},
{
Config: s.getFixture("database_0_create.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("database_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "kind", "db"),
resource.TestCheckResourceAttr(name, "metadata.expires", "2032-10-12T07:20:50Z"),
resource.TestCheckResourceAttr(name, "spec.protocol", "postgres"),
resource.TestCheckResourceAttr(name, "spec.uri", "example.com:5432"),
),
},
{
Config: s.getFixture("database_1_update.tf"),
PlanOnly: true,
},
},
})
}
func (s *TerraformSuite) TestImportDatabase() {
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
r := "teleport_database"
id := "test-import"
name := r + "." + id
database := &types.DatabaseV3{
Metadata: types.Metadata{
Name: id,
},
Spec: types.DatabaseSpecV3{
Protocol: "postgres",
URI: "localhost:3000/test",
},
}
err := database.CheckAndSetDefaults()
require.NoError(s.T(), err)
err = s.client.CreateDatabase(ctx, database)
require.NoError(s.T(), err)
require.Eventually(s.T(), func() bool {
_, err := s.client.GetDatabase(ctx, database.GetName())
if trace.IsNotFound(err) {
return false
}
require.NoError(s.T(), err)
return true
}, 5*time.Second, time.Second)
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.terraformConfig + "\n" + `resource "` + r + `" "` + id + `" { }`,
ResourceName: name,
ImportState: true,
ImportStateId: id,
ImportStateCheck: func(state []*terraform.InstanceState) error {
require.Equal(s.T(), state[0].Attributes["kind"], "db")
require.Equal(s.T(), state[0].Attributes["spec.uri"], "localhost:3000/test")
require.Equal(s.T(), state[0].Attributes["spec.protocol"], "postgres")
return nil
},
},
},
})
}
@@ -0,0 +1,137 @@
/*
Copyright 2015-2023 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"context"
"fmt"
// devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func (s *TerraformSuite) TestTrustedDevices() {
if !s.teleportFeatures.GetDeviceTrust().GetEnabled() {
s.T().Skip("Doesn't work in OSS version, requires Device Trust")
}
ctx, cancel := context.WithCancel(context.Background())
s.T().Cleanup(cancel)
device1 := "teleport_trusted_device.TESTDEVICE1"
device2 := "teleport_trusted_device.TESTDEVICE2"
allDevices := []string{device1, device2}
checkDeviceDestroyed := func(state *terraform.State) error {
for _, deviceName := range allDevices {
_, err := s.client.GetDeviceResource(ctx, deviceName)
switch {
case err == nil:
return fmt.Errorf("Device %s was not deleted", deviceName)
case trace.IsNotFound(err):
continue
default:
return err
}
}
return nil
}
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
CheckDestroy: checkDeviceDestroyed,
Steps: []resource.TestStep{
{
Config: s.getFixture("device_trust_0_create.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(device1, "spec.asset_tag", "TESTDEVICE1"),
resource.TestCheckResourceAttr(device1, "spec.os_type", "macos"),
resource.TestCheckResourceAttr(device1, "spec.enroll_status", "enrolled"),
),
},
{
Config: s.getFixture("device_trust_0_create.tf"),
PlanOnly: true,
},
{
Config: s.getFixture("device_trust_1_update.tf"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(device1, "spec.enroll_status", "not_enrolled"),
resource.TestCheckResourceAttr(device2, "spec.asset_tag", "TESTDEVICE2"),
resource.TestCheckResourceAttr(device2, "spec.os_type", "linux"),
resource.TestCheckResourceAttr(device2, "spec.enroll_status", "not_enrolled"),
),
},
{
Config: s.getFixture("device_trust_1_update.tf"),
PlanOnly: true,
},
},
})
}
func (s *TerraformSuite) TestImportTrustedDevices() {
if !s.teleportFeatures.GetDeviceTrust().GetEnabled() {
s.T().Skip("Doesn't work in OSS version, requires Device Trust")
}
ctx := context.Background()
r := "teleport_trusted_device"
id := "test_device"
deviceID := "1a6d1c46-cccf-4f58-8f67-85e6272ebef1"
name := r + "." + id
device := &types.DeviceV1{
ResourceHeader: types.ResourceHeader{
Kind: "device",
Metadata: types.Metadata{
Name: deviceID,
},
},
Spec: &types.DeviceSpec{
AssetTag: "DEVICE1",
OsType: "macos",
EnrollStatus: "not_enrolled",
},
}
_, err := s.client.CreateDeviceResource(ctx, device)
s.Require().NoError(err)
resource.Test(s.T(), resource.TestCase{
ProtoV6ProviderFactories: s.terraformProviders,
Steps: []resource.TestStep{
{
Config: s.terraformConfig + "\n" + `resource "` + r + `" "` + id + `" { }`,
ResourceName: name,
ImportState: true,
ImportStateId: deviceID,
ImportStateCheck: func(state []*terraform.InstanceState) error {
s.Require().Equal(state[0].Attributes["metadata.name"], deviceID)
s.Require().Equal(state[0].Attributes["kind"], "device")
s.Require().Equal(state[0].Attributes["spec.asset_tag"], "DEVICE1")
s.Require().Equal(state[0].Attributes["spec.os_type"], "macos")
s.Require().Equal(state[0].Attributes["spec.enroll_status"], "not_enrolled")
return nil
},
},
},
})
}
@@ -0,0 +1,35 @@
resource "teleport_access_list" "test" {
header = {
version = "v1"
metadata = {
name = "test"
labels = {
example = "yes"
}
}
}
spec = {
description = "test description"
owners = [
{
name = "gru"
description = "The supervillain."
}
]
membership_requires = {
roles = ["minion"]
}
ownership_requires = {
roles = ["supervillain"]
}
grants = {
roles = ["crane-operator"]
}
title = "Hello"
audit = {
recurrence = {
frequency = 3
}
}
}
}
@@ -0,0 +1,42 @@
resource "teleport_access_list" "test" {
header = {
version = "v1"
metadata = {
name = "test"
labels = {
example = "yes"
}
}
}
spec = {
description = "test description"
owners = [
{
name = "gru"
description = "The supervillain."
}
]
membership_requires = {
roles = ["minion"]
}
ownership_requires = {
roles = ["supervillain"]
}
grants = {
roles = ["crane-operator"]
traits = [{
key = "allowed-machines"
values = ["crane", "forklift"]
}]
}
title = "Hello"
audit = {
recurrence = {
frequency = 3
// changing day of the month should not change the next audit date
// it should take effect after the next review
day_of_month = 15
}
}
}
}
@@ -0,0 +1,41 @@
resource "teleport_access_list" "test" {
header = {
version = "v1"
metadata = {
name = "test"
labels = {
example = "yes"
}
expires = "2038-01-01T00:00:00Z"
}
}
spec = {
description = "test description"
owners = [
{
name = "gru"
description = "The supervillain."
}
]
membership_requires = {
roles = ["minion"]
}
ownership_requires = {
roles = ["supervillain"]
}
grants = {
roles = ["crane-operator"]
traits = [{
key = "allowed-machines"
values = ["crane", "forklift"]
}]
}
title = "Hello"
audit = {
recurrence = {
frequency = 3
day_of_month = 15
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
resource "teleport_app" "test" {
version = "v3"
metadata = {
name = "example"
description = "Test app"
labels = {
example = "yes"
"teleport.dev/origin" = "dynamic"
}
}
spec = {
uri = "localhost:3000"
}
}
@@ -0,0 +1,15 @@
resource "teleport_app" "test_auth_b64" {
version = "v3"
metadata = {
name = "test_auth_b64"
description = "Test app"
labels = {
example = "yes"
"teleport.dev/origin" = "dynamic"
}
}
spec = {
uri = "localhost:3000"
}
}
@@ -0,0 +1,15 @@
resource "teleport_app" "test_auth_files" {
version = "v3"
metadata = {
name = "test_auth_files"
description = "Test app"
labels = {
example = "yes"
"teleport.dev/origin" = "dynamic"
}
}
spec = {
uri = "localhost:3000"
}
}
@@ -0,0 +1,15 @@
resource "teleport_app" "test_with_cache" {
version = "v3"
metadata = {
name = "example"
description = "Test app"
labels = {
example = "yes"
"teleport.dev/origin" = "dynamic"
}
}
spec = {
uri = "localhost:3000"
}
}

Some files were not shown because too many files have changed in this diff Show More