Terraform: convert database to generic provider (#69396)

Contributes to https://github.com/gravitational/teleport/issues/69301.
This commit is contained in:
rosstimothy
2026-08-07 14:37:15 +00:00
committed by GitHub
parent 0930cd5154
commit 13be5bd0fe
7 changed files with 143 additions and 513 deletions
-17
View File
@@ -294,21 +294,6 @@ var (
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,
}
dynamicWindowsDesktop = payload{
Name: "DynamicWindowsDesktop",
TypeName: "DynamicWindowsDesktopV1",
@@ -1109,8 +1094,6 @@ func genTFSchema() {
generateDataSource(clusterMaintenance, singularDataSource)
generateResource(clusterNetworking, singularResource)
generateDataSource(clusterNetworking, singularDataSource)
generateResource(database, pluralResource)
generateDataSource(database, pluralDataSource)
generateResource(dynamicWindowsDesktop, pluralResource)
generateDataSource(dynamicWindowsDesktop, pluralDataSource)
generateResource(githubConnector, pluralResource)
@@ -1,97 +0,0 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2024 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 legacy
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"
"github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdiag"
)
// 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(tfdiag.DiagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
var state types.Object
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
// Todo: Remove after updating terraform-plugin to >=v1.5.0.
// terraform-plugin-testing version <1.5.0 requires data resources to
// implement the 'id' attribute.
// https://developer.hashicorp.com/terraform/plugin/framework/acctests#no-id-found-in-attributes
v, ok := state.Attrs["id"]
if !ok || v.IsNull() {
state.Attrs["id"] = id
}
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
}
}
@@ -24,7 +24,6 @@ func DataSourceTypes() map[string]tfsdk.DataSourceType {
"teleport_app_auth_config": dataSourceTeleportAppAuthConfigType{},
"teleport_cluster_maintenance_config": dataSourceTeleportClusterMaintenanceConfigType{},
"teleport_cluster_networking_config": dataSourceTeleportClusterNetworkingConfigType{},
"teleport_database": dataSourceTeleportDatabaseType{},
"teleport_discovery_config": dataSourceTeleportDiscoveryConfigType{},
"teleport_dynamic_windows_desktop": dataSourceTeleportDynamicWindowsDesktopType{},
"teleport_github_connector": dataSourceTeleportGithubConnectorType{},
@@ -69,7 +68,6 @@ func ResourceTypes() map[string]tfsdk.ResourceType {
"teleport_app_auth_config": resourceTeleportAppAuthConfigType{},
"teleport_cluster_maintenance_config": resourceTeleportClusterMaintenanceConfigType{},
"teleport_cluster_networking_config": resourceTeleportClusterNetworkingConfigType{},
"teleport_database": resourceTeleportDatabaseType{},
"teleport_discovery_config": resourceTeleportDiscoveryConfigType{},
"teleport_dynamic_windows_desktop": resourceTeleportDynamicWindowsDesktopType{},
"teleport_github_connector": resourceTeleportGithubConnectorType{},
@@ -1,397 +0,0 @@
// Code generated by _gen/main.go DO NOT EDIT
/*
Copyright 2015-2024 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 legacy
import (
"context"
"fmt"
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"
"github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdiag"
)
// 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(tfdiag.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(tfdiag.DiagFromErr("Database exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
err = r.p.Client().CreateDatabase(ctx, databaseResource)
if err != nil {
resp.Diagnostics.Append(tfdiag.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
// Try getting the resource until it exists.
tries := 0
retry, err := r.p.Retry()
if err != nil {
return
}
for {
tries = tries + 1
databaseI, err = r.p.Client().GetDatabase(ctx, id)
if trace.IsNotFound(err) {
select {
case <-ctx.Done():
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Database", trace.Wrap(ctx.Err()), "db"))
return
case <-retry.After():
}
if tries >= r.p.MaxRetries() {
diagMessage := fmt.Sprintf("Error reading Database (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "db")
return
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Database", trace.Wrap(err), "db"))
return
}
databaseResource, ok := databaseI.(*apitypes.DatabaseV3)
if !ok {
resp.Diagnostics.Append(tfdiag.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(tfdiag.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(tfdiag.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(tfdiag.DiagFromWrappedErr("Error reading Database", err, "db"))
return
}
err = r.p.Client().UpdateDatabase(ctx, databaseResource)
if err != nil {
resp.Diagnostics.Append(tfdiag.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
retry, err := r.p.Retry()
if err != nil {
return
}
for {
tries = tries + 1
databaseI, err = r.p.Client().GetDatabase(ctx, name)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Database", err, "db"))
return
}
if databaseBefore.GetMetadata().Revision != databaseI.GetMetadata().Revision || false {
break
}
select {
case <-ctx.Done():
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Database", trace.Wrap(ctx.Err()), "db"))
return
case <-retry.After():
}
if tries >= r.p.MaxRetries() {
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(tfdiag.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
}
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(tfdiag.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(tfdiag.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
}
}
// ModifyPlan modifies the planned value, normalizing null values.
func (r resourceTeleportDatabase) ModifyPlan(ctx context.Context, req tfsdk.ModifyResourcePlanRequest, resp *tfsdk.ModifyResourcePlanResponse) {
// If the entire plan is null, the resource is planned for destruction.
if req.Plan.Raw.IsNull() {
return
}
// If the state is null, the resource is being created. No need to modify plan.
if req.State.Raw.IsNull() {
return
}
var config types.Object
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
database := &apitypes.DatabaseV3{}
resp.Diagnostics.Append(tfschema.CopyDatabaseV3FromTerraform(ctx, config, database)...)
if resp.Diagnostics.HasError() {
return
}
databaseResource := database
if err := databaseResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error setting Database defaults", trace.Wrap(err), "db"))
return
}
database = databaseResource
const preserveUnknown = true
resp.Diagnostics.Append(tfschema.CopyDatabaseV3ToTerraformPreserveUnknown(ctx, database, &config, preserveUnknown)...)
if resp.Diagnostics.HasError() {
return
}
var plan types.Object
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["spec"] = config.Attrs["spec"]
resp.Diagnostics.Append(resp.Plan.Set(ctx, &plan)...)
}
@@ -0,0 +1,65 @@
// Teleport
// Copyright (C) 2026 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package resources
import (
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
apitypes "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/terraform/provider/internal/teleport"
"github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdriver"
"github.com/gravitational/teleport/integrations/terraform/tfschema"
)
// NewDatabaseDataSourceType returns the database data source type.
func NewDatabaseDataSourceType() tfdriver.DataSourceType[apitypes.DatabaseV3, tfdriver.NameIdentifier] {
return tfdriver.DataSourceType[apitypes.DatabaseV3, tfdriver.NameIdentifier]{
NewDataSourceClient: func(p tfsdk.Provider) tfdriver.DataSourceClient[apitypes.DatabaseV3, tfdriver.NameIdentifier] {
return teleport.NewDatabaseClient(clientFromProvider(p))
},
Kind: apitypes.KindDatabase,
Codec: tfdriver.DataSourceCodecFuncs[apitypes.DatabaseV3]{
SchemaFunc: tfschema.GenSchemaDatabaseV3,
ToStateFunc: tfschema.CopyDatabaseV3ToTerraform,
},
Identifier: tfdriver.NameIdentifierFromPath(path.Root("metadata").AtName("name")),
}
}
// NewDatabaseResourceType returns the database resource type.
func NewDatabaseResourceType() tfdriver.ResourceType[apitypes.DatabaseV3, tfdriver.NameIdentifier] {
return tfdriver.ResourceType[apitypes.DatabaseV3, tfdriver.NameIdentifier]{
NewResourceClient: func(p tfsdk.Provider) tfdriver.ResourceClient[apitypes.DatabaseV3, tfdriver.NameIdentifier] {
return teleport.NewDatabaseClient(clientFromProvider(p))
},
Kind: apitypes.KindDatabase,
Codec: tfdriver.ResourceCodecFuncs[apitypes.DatabaseV3]{
SchemaFunc: tfschema.GenSchemaDatabaseV3,
ToStateFunc: tfschema.CopyDatabaseV3ToTerraform,
FromPlanFunc: tfschema.CopyDatabaseV3FromTerraform,
},
Normalizer: tfdriver.CheckAndSetDefaults[apitypes.DatabaseV3](),
Identifier: tfdriver.NameIdentifierPolicy(path.Root("metadata").AtName("name"), func(database *apitypes.DatabaseV3) string {
return database.GetMetadata().Name
}),
ResourceRevision: func(st *apitypes.DatabaseV3) string {
return st.GetMetadata().Revision
},
}
}
@@ -0,0 +1,76 @@
// Teleport
// Copyright (C) 2026 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package teleport
import (
"context"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdriver"
)
// NewDatabaseClient returns a database client.
func NewDatabaseClient(c *client.Client) DatabaseClient {
return DatabaseClient{client: c}
}
// DatabaseClient manages database resources.
type DatabaseClient struct {
client *client.Client
}
// Get reads a database by name.
func (r DatabaseClient) Get(ctx context.Context, id tfdriver.NameIdentifier) (*types.DatabaseV3, error) {
database, err := r.client.GetDatabase(ctx, id.Name)
if err != nil {
return nil, trace.Wrap(err)
}
databasev3, ok := database.(*types.DatabaseV3)
if !ok {
return nil, trace.BadParameter("unexpected database type: %T", database)
}
return databasev3, nil
}
// Create creates a database.
func (r DatabaseClient) Create(ctx context.Context, database *types.DatabaseV3) error {
if err := r.client.CreateDatabase(ctx, database); err != nil {
return trace.Wrap(err)
}
return nil
}
// Upsert updates a database.
func (r DatabaseClient) Upsert(ctx context.Context, database *types.DatabaseV3) error {
if err := r.client.UpdateDatabase(ctx, database); err != nil {
return trace.Wrap(err)
}
return nil
}
// Delete deletes a database by name.
func (r DatabaseClient) Delete(ctx context.Context, id tfdriver.NameIdentifier) error {
return trace.Wrap(r.client.DeleteDatabase(ctx, id.Name))
}
@@ -568,6 +568,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp
"teleport_access_list_member": resources.NewAccessListMemberResourceType(),
"teleport_app": resources.NewAppResourceType(),
"teleport_auth_preference": resources.NewAuthPreferenceResourceType(),
"teleport_database": resources.NewDatabaseResourceType(),
"teleport_kube_cluster": resources.NewKubernetesClusterResourceType(),
"teleport_saml_connector": resources.NewSAMLConnectorResourceType(),
"teleport_scoped_role": resources.NewScopedRoleResourceType(),
@@ -589,6 +590,7 @@ func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourc
"teleport_access_list_member": resources.NewAccessListMemberDataSourceType(),
"teleport_app": resources.NewAppDataSourceType(),
"teleport_auth_preference": resources.NewAuthPreferenceDataSourceType(),
"teleport_database": resources.NewDatabaseDataSourceType(),
"teleport_kube_cluster": resources.NewKubernetesClusterDataSourceType(),
"teleport_saml_connector": resources.NewSAMLConnectorDataSourceType(),
"teleport_scoped_role": resources.NewScopedRoleDataSourceType(),