Terraform: convert installer to generic provider (#69403)

Contributes to https://github.com/gravitational/teleport/issues/69301.
This commit is contained in:
rosstimothy
2026-08-07 17:01:12 +00:00
committed by GitHub
parent 9d29ffb5c5
commit 94ee3ab815
7 changed files with 143 additions and 513 deletions
-17
View File
@@ -526,21 +526,6 @@ var (
ForceSetKind: "apitypes.KindNode",
}
installer = payload{
Name: "Installer",
TypeName: "InstallerV1",
VarName: "installer",
GetMethod: "GetInstaller",
CreateMethod: "SetInstaller",
UpdateMethod: "SetInstaller",
DeleteMethod: "DeleteInstaller",
ID: `"installer"`,
Kind: "installer",
HasStaticID: false,
TerraformResourceType: "teleport_installer",
HasCheckAndSetDefaults: true,
}
accessMonitoringRule = payload{
Name: "AccessMonitoringRule",
TypeName: "AccessMonitoringRule",
@@ -1062,8 +1047,6 @@ func genTFSchema() {
generateDataSource(oktaImportRule, pluralDataSource)
generateResource(server, pluralResource)
generateDataSource(server, pluralDataSource)
generateResource(installer, pluralResource)
generateDataSource(installer, pluralDataSource)
generateResource(accessMonitoringRule, pluralResource)
generateDataSource(accessMonitoringRule, pluralDataSource)
generateResource(workloadIdentity, 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"
)
// dataSourceTeleportInstallerType is the data source metadata type
type dataSourceTeleportInstallerType struct{}
// dataSourceTeleportInstaller is the resource
type dataSourceTeleportInstaller struct {
p Provider
}
// GetSchema returns the data source schema
func (r dataSourceTeleportInstallerType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaInstallerV1(ctx)
}
// NewDataSource creates the empty data source
func (r dataSourceTeleportInstallerType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) {
return dataSourceTeleportInstaller{
p: p.(Provider),
}, nil
}
// Read reads teleport Installer
func (r dataSourceTeleportInstaller) 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
}
installerI, err := r.p.Client().GetInstaller(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer"))
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
}
installer := installerI.(*apitypes.InstallerV1)
diags = tfschema.CopyInstallerV1ToTerraform(ctx, installer, &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
}
}
@@ -37,7 +37,6 @@ func DataSourceTypes() map[string]tfsdk.DataSourceType {
"teleport_login_rule": dataSourceTeleportLoginRuleType{},
"teleport_trusted_device": dataSourceTeleportDeviceV1Type{},
"teleport_okta_import_rule": dataSourceTeleportOktaImportRuleType{},
"teleport_installer": dataSourceTeleportInstallerType{},
"teleport_access_monitoring_rule": dataSourceTeleportAccessMonitoringRuleType{},
"teleport_workload_identity": dataSourceTeleportWorkloadIdentityType{},
"teleport_autoupdate_version": dataSourceTeleportAutoUpdateVersionType{},
@@ -80,7 +79,6 @@ func ResourceTypes() map[string]tfsdk.ResourceType {
"teleport_trusted_device": resourceTeleportDeviceV1Type{},
"teleport_okta_import_rule": resourceTeleportOktaImportRuleType{},
"teleport_server": resourceTeleportServerType{},
"teleport_installer": resourceTeleportInstallerType{},
"teleport_access_monitoring_rule": resourceTeleportAccessMonitoringRuleType{},
"teleport_workload_identity": resourceTeleportWorkloadIdentityType{},
"teleport_autoupdate_version": resourceTeleportAutoUpdateVersionType{},
@@ -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"
)
// resourceTeleportInstallerType is the resource metadata type
type resourceTeleportInstallerType struct{}
// resourceTeleportInstaller is the resource
type resourceTeleportInstaller struct {
p Provider
}
// GetSchema returns the resource schema
func (r resourceTeleportInstallerType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfschema.GenSchemaInstallerV1(ctx)
}
// NewResource creates the empty resource
func (r resourceTeleportInstallerType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceTeleportInstaller{
p: p.(Provider),
}, nil
}
// Create creates the Installer
func (r resourceTeleportInstaller) 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
}
installer := &apitypes.InstallerV1{}
diags = tfschema.CopyInstallerV1FromTerraform(ctx, plan, installer)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
installerResource := installer
err = installerResource.CheckAndSetDefaults()
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error setting Installer defaults", trace.Wrap(err), "installer"))
return
}
id := installerResource.Metadata.Name
_, err = r.p.Client().GetInstaller(ctx, id)
if !trace.IsNotFound(err) {
if err == nil {
existErr := fmt.Sprintf("Installer exists in Teleport. Either remove it (tctl rm installer/%v)"+
" or import it to the existing state (terraform import teleport_installer.%v %v)", id, id, id)
resp.Diagnostics.Append(tfdiag.DiagFromErr("Installer exists in Teleport", trace.Errorf(existErr)))
return
}
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer"))
return
}
err = r.p.Client().SetInstaller(ctx, installerResource)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error creating Installer", trace.Wrap(err), "installer"))
return
}
// Not really an inferface, just using the same name for easier templating.
var installerI apitypes.Installer
// Try getting the resource until it exists.
tries := 0
retry, err := r.p.Retry()
if err != nil {
return
}
for {
tries = tries + 1
installerI, err = r.p.Client().GetInstaller(ctx, id)
if trace.IsNotFound(err) {
select {
case <-ctx.Done():
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(ctx.Err()), "installer"))
return
case <-retry.After():
}
if tries >= r.p.MaxRetries() {
diagMessage := fmt.Sprintf("Error reading Installer (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "installer")
return
}
continue
}
break
}
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer"))
return
}
installerResource, ok := installerI.(*apitypes.InstallerV1)
if !ok {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Errorf("Can not convert %T to InstallerV1", installerI), "installer"))
return
}
installer = installerResource
diags = tfschema.CopyInstallerV1ToTerraform(ctx, installer, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
plan.Attrs["id"] = types.String{Value: "installer"}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read reads teleport Installer
func (r resourceTeleportInstaller) 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
}
installerI, err := r.p.Client().GetInstaller(ctx, id.Value)
if trace.IsNotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer"))
return
}
installer := installerI.(*apitypes.InstallerV1)
diags = tfschema.CopyInstallerV1ToTerraform(ctx, installer, &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 Installer
func (r resourceTeleportInstaller) 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
}
installer := &apitypes.InstallerV1{}
diags = tfschema.CopyInstallerV1FromTerraform(ctx, plan, installer)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
installerResource := installer
if err := installerResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error updating Installer", err, "installer"))
return
}
name := installerResource.Metadata.Name
installerBefore, err := r.p.Client().GetInstaller(ctx, name)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", err, "installer"))
return
}
err = r.p.Client().SetInstaller(ctx, installerResource)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error updating Installer", err, "installer"))
return
}
// Not really an inferface, just using the same name for easier templating.
var installerI apitypes.Installer
tries := 0
retry, err := r.p.Retry()
if err != nil {
return
}
for {
tries = tries + 1
installerI, err = r.p.Client().GetInstaller(ctx, name)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", err, "installer"))
return
}
if installerBefore.GetMetadata().Revision != installerI.GetMetadata().Revision || false {
break
}
select {
case <-ctx.Done():
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(ctx.Err()), "installer"))
return
case <-retry.After():
}
if tries >= r.p.MaxRetries() {
diagMessage := fmt.Sprintf("Error reading Installer (tried %d times) - state outdated, please import resource", tries)
resp.Diagnostics.AddError(diagMessage, "installer")
return
}
}
installerResource, ok := installerI.(*apitypes.InstallerV1)
if !ok {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Errorf("Can not convert %T to InstallerV1", installerI), "installer"))
return
}
installer = installerResource
diags = tfschema.CopyInstallerV1ToTerraform(ctx, installer, &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 Installer
func (r resourceTeleportInstaller) 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().DeleteInstaller(ctx, id.Value)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error deleting InstallerV1", trace.Wrap(err), "installer"))
return
}
resp.State.RemoveResource(ctx)
}
// ImportState imports Installer state
func (r resourceTeleportInstaller) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
installer, err := r.p.Client().GetInstaller(ctx, req.ID)
if err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer"))
return
}
installerResource := installer.(*apitypes.InstallerV1)
var state types.Object
diags := resp.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = tfschema.CopyInstallerV1ToTerraform(ctx, installerResource, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
id := installerResource.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 resourceTeleportInstaller) 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
}
installer := &apitypes.InstallerV1{}
resp.Diagnostics.Append(tfschema.CopyInstallerV1FromTerraform(ctx, config, installer)...)
if resp.Diagnostics.HasError() {
return
}
installerResource := installer
if err := installerResource.CheckAndSetDefaults(); err != nil {
resp.Diagnostics.Append(tfdiag.DiagFromWrappedErr("Error setting Installer defaults", trace.Wrap(err), "installer"))
return
}
installer = installerResource
const preserveUnknown = true
resp.Diagnostics.Append(tfschema.CopyInstallerV1ToTerraformPreserveUnknown(ctx, installer, &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"
"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"
)
// NewInstallerDataSourceType returns the installer data source type.
func NewInstallerDataSourceType() tfdriver.DataSourceType[types.InstallerV1, tfdriver.NameIdentifier] {
return tfdriver.DataSourceType[types.InstallerV1, tfdriver.NameIdentifier]{
NewDataSourceClient: func(p tfsdk.Provider) tfdriver.DataSourceClient[types.InstallerV1, tfdriver.NameIdentifier] {
return teleport.NewInstallerClient(clientFromProvider(p))
},
Kind: types.KindInstaller,
Codec: tfdriver.DataSourceCodecFuncs[types.InstallerV1]{
SchemaFunc: tfschema.GenSchemaInstallerV1,
ToStateFunc: tfschema.CopyInstallerV1ToTerraform,
},
Identifier: tfdriver.NameIdentifierFromPath(path.Root("metadata").AtName("name")),
}
}
// NewInstallerResourceType returns the installer resource type.
func NewInstallerResourceType() tfdriver.ResourceType[types.InstallerV1, tfdriver.NameIdentifier] {
return tfdriver.ResourceType[types.InstallerV1, tfdriver.NameIdentifier]{
NewResourceClient: func(p tfsdk.Provider) tfdriver.ResourceClient[types.InstallerV1, tfdriver.NameIdentifier] {
return teleport.NewInstallerClient(clientFromProvider(p))
},
Kind: types.KindInstaller,
Codec: tfdriver.ResourceCodecFuncs[types.InstallerV1]{
SchemaFunc: tfschema.GenSchemaInstallerV1,
ToStateFunc: tfschema.CopyInstallerV1ToTerraform,
FromPlanFunc: tfschema.CopyInstallerV1FromTerraform,
},
Normalizer: tfdriver.CheckAndSetDefaults[types.InstallerV1](),
Identifier: tfdriver.NameIdentifierPolicy(path.Root("metadata").AtName("name"), func(installer *types.InstallerV1) string {
return installer.GetMetadata().Name
}),
ResourceRevision: func(st *types.InstallerV1) 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"
)
// NewInstallerClient returns an installer client.
func NewInstallerClient(c *client.Client) InstallerClient {
return InstallerClient{client: c}
}
// InstallerClient manages installer resources.
type InstallerClient struct {
client *client.Client
}
// Get reads an installer by name.
func (r InstallerClient) Get(ctx context.Context, id tfdriver.NameIdentifier) (*types.InstallerV1, error) {
installer, err := r.client.GetInstaller(ctx, id.Name)
if err != nil {
return nil, trace.Wrap(err)
}
installerv1, ok := installer.(*types.InstallerV1)
if !ok {
return nil, trace.BadParameter("unexpected installer type: %T", installer)
}
return installerv1, nil
}
// Create creates an installer.
func (r InstallerClient) Create(ctx context.Context, installer *types.InstallerV1) error {
if err := r.client.SetInstaller(ctx, installer); err != nil {
return trace.Wrap(err)
}
return nil
}
// Upsert updates an installer.
func (r InstallerClient) Upsert(ctx context.Context, installer *types.InstallerV1) error {
if err := r.client.SetInstaller(ctx, installer); err != nil {
return trace.Wrap(err)
}
return nil
}
// Delete deletes an installer by name.
func (r InstallerClient) Delete(ctx context.Context, id tfdriver.NameIdentifier) error {
return trace.Wrap(r.client.DeleteInstaller(ctx, id.Name))
}
@@ -569,6 +569,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp
"teleport_app": resources.NewAppResourceType(),
"teleport_auth_preference": resources.NewAuthPreferenceResourceType(),
"teleport_database": resources.NewDatabaseResourceType(),
"teleport_installer": resources.NewInstallerResourceType(),
"teleport_kube_cluster": resources.NewKubernetesClusterResourceType(),
"teleport_lock": resources.NewLockResourceType(),
"teleport_saml_connector": resources.NewSAMLConnectorResourceType(),
@@ -594,6 +595,7 @@ func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourc
"teleport_app": resources.NewAppDataSourceType(),
"teleport_auth_preference": resources.NewAuthPreferenceDataSourceType(),
"teleport_database": resources.NewDatabaseDataSourceType(),
"teleport_installer": resources.NewInstallerDataSourceType(),
"teleport_kube_cluster": resources.NewKubernetesClusterDataSourceType(),
"teleport_lock": resources.NewLockDataSourceType(),
"teleport_saml_connector": resources.NewSAMLConnectorDataSourceType(),