diff --git a/docs/pages/admin-guides/infrastructure-as-code/terraform-provider.mdx b/docs/pages/admin-guides/infrastructure-as-code/terraform-provider.mdx index b93f1b66b15ea..ed6372ab74522 100644 --- a/docs/pages/admin-guides/infrastructure-as-code/terraform-provider.mdx +++ b/docs/pages/admin-guides/infrastructure-as-code/terraform-provider.mdx @@ -82,6 +82,7 @@ authority to manage resources in the cluster. To prepare credentials using a loc - user - access_list - node + - installer verbs: ['list','create','read','update','delete'] version: v7 ``` diff --git a/integrations/terraform/README.md b/integrations/terraform/README.md index bcf481a0f02fc..e927011a19d2b 100644 --- a/integrations/terraform/README.md +++ b/integrations/terraform/README.md @@ -2,7 +2,7 @@ ## Usage -Please, refer to [official documentation](https://goteleport.com/docs/setup/guides/terraform-provider/). +Please, refer to [official documentation](https://goteleport.com/docs/admin-guides/infrastructure-as-code/terraform-provider/). ## Development diff --git a/integrations/terraform/example/installer.tf.example b/integrations/terraform/example/installer.tf.example new file mode 100644 index 0000000000000..dc69e7917937b --- /dev/null +++ b/integrations/terraform/example/installer.tf.example @@ -0,0 +1,70 @@ +# Teleport Installer resource + +resource "teleport_installer" "example" { + version = "v1" + metadata = { + name = "example" + description = "Example Teleport Installer" + labels = { + example = "yes" + } + } + + spec = { + # This is the default installer script. For more details about the installer script + # see https://goteleport.com/docs/enroll-resources/auto-discovery/servers/ec2-discovery/#step-67-optional-customize-the-default-installer-script + script = <&2 + return 1 + fi; + + if [ $${ARCH} = "armv7l" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-arm-bin.tar.gz" + elif [ $${ARCH} = "aarch64" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-arm64-bin.tar.gz" + elif [ $${ARCH} = "x86_64" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-amd64-bin.tar.gz" + elif [ $${ARCH} = "i686" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-386-bin.tar.gz" + else + echo "Invalid Linux architecture $${ARCH}." >&2 + return 1 + fi; +} + +main() { + tarballName=$(teleportTarballName) + echo "Downloading from $${cdnBaseURL}/$${tarballName} and extracting teleport to $${tempDir} ..." + curl --show-error --fail --location $${cdnBaseURL}/$${tarballName} | tar xzf - -C $${tempDir} $${teleportFlavor}/teleport + + mkdir -p $${tempDir}/bin + mv $${tempDir}/$${teleportFlavor}/teleport $${tempDir}/bin/teleport + echo "> $${tempDir}/bin/teleport $${teleportArgs} $@" + sudo $${tempDir}/bin/teleport $${teleportArgs} $@ && echo $successMessage +} + +main $@ +EOF + } +} diff --git a/integrations/terraform/example/terraform.yaml b/integrations/terraform/example/terraform.yaml index 608d274bcaebe..6350d2efd3b95 100644 --- a/integrations/terraform/example/terraform.yaml +++ b/integrations/terraform/example/terraform.yaml @@ -29,6 +29,7 @@ spec: - device - okta_import_rule - access_list + - installer verbs: ['list','create','read','update','delete'] version: v6 --- diff --git a/integrations/terraform/gen/main.go b/integrations/terraform/gen/main.go index 047a3d7213e0e..65fb98a334281 100644 --- a/integrations/terraform/gen/main.go +++ b/integrations/terraform/gen/main.go @@ -455,6 +455,21 @@ var ( Namespaced: true, 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, + } ) func main() { @@ -502,6 +517,8 @@ func genTFSchema() { generateDataSource(accessList, pluralDataSource) generateResource(server, pluralResource) generateDataSource(server, pluralDataSource) + generateResource(installer, pluralResource) + generateDataSource(installer, pluralDataSource) } func generateResource(p payload, tpl string) { @@ -574,6 +591,7 @@ var ( "trusted_cluster": tfschema.GenSchemaTrustedClusterV2, "user": tfschema.GenSchemaUserV2, "server": tfschema.GenSchemaServerV2, + "installer": tfschema.GenSchemaInstallerV1, } // hiddenFields are fields that are not outputted to the reference doc. diff --git a/integrations/terraform/protoc-gen-terraform-teleport.yaml b/integrations/terraform/protoc-gen-terraform-teleport.yaml index 3468d2f4ec2a2..b532749d63783 100644 --- a/integrations/terraform/protoc-gen-terraform-teleport.yaml +++ b/integrations/terraform/protoc-gen-terraform-teleport.yaml @@ -20,8 +20,9 @@ types: - "SessionRecordingConfigV2" - "TrustedClusterV2" - "UserV2" + - "InstallerV1" -# id field is required for integration tests. It is not used by provider. +# 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: @@ -122,6 +123,13 @@ injected_fields: computed: true plan_modifiers: - "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()" + InstallerV1: + - + 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: @@ -255,7 +263,7 @@ computed_fields: # back into the state. - "ServerV2.Metadata" - # Session recording + # Session recording - "SessionRecordingConfigV2.Spec.Mode" - "SessionRecordingConfigV2.Kind" @@ -265,7 +273,10 @@ computed_fields: # User - "UserV2.Kind" -# These fields will be marked as Required: true + # Installer + - "InstallerV1.Kind" + +# These fields will be marked as Required: true required_fields: # App - "AppV3.Metadata.Name" @@ -276,8 +287,8 @@ required_fields: - "AuthPreferenceV2.Metadata.Name" # Database - - "DatabaseV3.Spec.Protocol" - - "DatabaseV3.Spec.URI" + - "DatabaseV3.Spec.Protocol" + - "DatabaseV3.Spec.URI" - "DatabaseV3.Metadata.Name" - "DatabaseV3.Version" @@ -326,12 +337,18 @@ required_fields: - "ClusterMaintenanceConfigV1.Version" - "AuthPreferenceV2.Version" + # Installer + - "InstallerV1.Spec" + - "InstallerV1.Spec.Script" + - "InstallerV1.Metadata.Name" + - "InstallerV1.Version" + # These fields must be marked as sensitive sensitive_fields: - "SAMLConnectorV2.Spec.Cert" - "SAMLConnectorV2.Spec.SigningKeyPair.PrivateKey" - "SAMLConnectorV2.Spec.EncryptionKeyPair.PrivateKey" - - "SAMLConnectorV2.Spec.EntityDescriptor" + - "SAMLConnectorV2.Spec.EntityDescriptor" - "GithubConnectorV3.Spec.ClientSecret" - "OIDCConnectorV3.Spec.ClientSecret" - "OIDCConnectorV3.Spec.GoogleServiceAccount" @@ -394,13 +411,15 @@ validators: - UseVersionBetween(2,2) ClusterMaintenanceConfigV1.Version: - UseVersionBetween(1,1) + InstallerV1.Version: + - UseVersionBetween(1,1) time_type: type: "TimeType" value_type: "TimeValue" cast_to_type: "time.Time" cast_from_type: "time.Time" - type_constructor: UseRFC3339Time() + type_constructor: UseRFC3339Time() duration_type: type: "DurationType" diff --git a/integrations/terraform/provider/data_source_teleport_installer.go b/integrations/terraform/provider/data_source_teleport_installer.go new file mode 100755 index 0000000000000..3aa6321212f77 --- /dev/null +++ b/integrations/terraform/provider/data_source_teleport_installer.go @@ -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" +) + +// 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(diagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer")) + return + } + + var state types.Object + + 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 + } +} diff --git a/integrations/terraform/provider/provider.go b/integrations/terraform/provider/provider.go index 655ced6492d9c..1e5f130e02cef 100644 --- a/integrations/terraform/provider/provider.go +++ b/integrations/terraform/provider/provider.go @@ -583,6 +583,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp "teleport_okta_import_rule": resourceTeleportOktaImportRuleType{}, "teleport_access_list": resourceTeleportAccessListType{}, "teleport_server": resourceTeleportServerType{}, + "teleport_installer": resourceTeleportInstallerType{}, }, nil } @@ -606,5 +607,6 @@ func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourc "teleport_trusted_device": dataSourceTeleportDeviceV1Type{}, "teleport_okta_import_rule": dataSourceTeleportOktaImportRuleType{}, "teleport_access_list": dataSourceTeleportAccessListType{}, + "teleport_installer": dataSourceTeleportInstallerType{}, }, nil } diff --git a/integrations/terraform/provider/resource_teleport_installer.go b/integrations/terraform/provider/resource_teleport_installer.go new file mode 100755 index 0000000000000..4fdd25ad0a120 --- /dev/null +++ b/integrations/terraform/provider/resource_teleport_installer.go @@ -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" +) + +// 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(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(diagFromErr("Installer exists in Teleport", trace.Errorf(existErr))) + return + } + + resp.Diagnostics.Append(diagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer")) + return + } + + err = r.p.Client.SetInstaller(ctx, installerResource) + if err != nil { + resp.Diagnostics.Append(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 + tries := 0 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + installerI, err = r.p.Client.GetInstaller(ctx, id) + if trace.IsNotFound(err) { + if bErr := backoff.Do(ctx); bErr != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading Installer", trace.Wrap(bErr), "installer")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading Installer (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "installer") + } + continue + } + break + } + + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer")) + return + } + + installerResource, ok := installerI.(*apitypes.InstallerV1) + if !ok { + resp.Diagnostics.Append(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(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(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(diagFromWrappedErr("Error reading Installer", err, "installer")) + return + } + + err = r.p.Client.SetInstaller(ctx, installerResource) + if err != nil { + resp.Diagnostics.Append(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 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + installerI, err = r.p.Client.GetInstaller(ctx, name) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading Installer", err, "installer")) + return + } + if installerBefore.GetMetadata().Revision != installerI.GetMetadata().Revision || false { + break + } + + if err := backoff.Do(ctx); err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading Installer", trace.Wrap(err), "installer")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + 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(diagFromWrappedErr("Error reading Installer", trace.Errorf("Can not convert %T to InstallerV1", installerI), "installer")) + return + } + 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(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(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 + } +} diff --git a/integrations/terraform/reference.mdx b/integrations/terraform/reference.mdx index 77a59f85f1d93..26fa663c925b9 100755 --- a/integrations/terraform/reference.mdx +++ b/integrations/terraform/reference.mdx @@ -15,6 +15,7 @@ Supported resources: - [teleport_cluster_networking_config](#teleport_cluster_networking_config) - [teleport_database](#teleport_database) - [teleport_github_connector](#teleport_github_connector) +- [teleport_installer](#teleport_installer) - [teleport_login_rule](#teleport_login_rule) - [teleport_oidc_connector](#teleport_oidc_connector) - [teleport_okta_import_rule](#teleport_okta_import_rule) @@ -1118,6 +1119,112 @@ resource "teleport_github_connector" "github" { ``` +## teleport_installer + +| Name | Type | Required | Description | +|----------|--------|----------|------------------------------------------------------------------------------| +| metadata | object | | Metadata is the resource metadata. | +| spec | object | * | Spec is the resource spec. | +| sub_kind | string | | SubKind is an optional resource subkind. Currently unused for this resource. | +| version | string | * | Version is the resource version. | + +### metadata + +Metadata is the resource metadata. + +| Name | Type | Required | Description | +|-------------|----------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| description | string | | Description is object description | +| expires | RFC3339 time | | Expires is a global expiry time header can be set on any resource in the system. | +| labels | map of strings | | Labels is a set of labels | +| name | string | * | Name is an object name | +| namespace | string | | Namespace is object namespace. The field should be called "namespace" when it returns in Teleport 2.4. | +| revision | string | | Revision is an opaque identifier which tracks the versions of a resource over time. Clients should ignore and not alter its value but must return the revision in any updates of a resource. | + +### spec + +Spec is the resource spec. + +| Name | Type | Required | Description | +|--------|--------|----------|------------------------------------------------------------| +| script | string | * | Script represents the contents of a installer shell script | + +Example: + +``` +# Teleport Installer resource + +resource "teleport_installer" "example" { + version = "v1" + metadata = { + name = "example" + description = "Example Teleport Installer" + labels = { + example = "yes" + } + } + + spec = { + # This is the default installer script. For more details about the installer script + # see https://goteleport.com/docs/enroll-resources/auto-discovery/servers/ec2-discovery/#step-67-optional-customize-the-default-installer-script + script = <&2 + return 1 + fi; + + if [ $${ARCH} = "armv7l" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-arm-bin.tar.gz" + elif [ $${ARCH} = "aarch64" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-arm64-bin.tar.gz" + elif [ $${ARCH} = "x86_64" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-amd64-bin.tar.gz" + elif [ $${ARCH} = "i686" ]; then echo "$${teleportFlavor}-$${teleportVersion}-linux-386-bin.tar.gz" + else + echo "Invalid Linux architecture $${ARCH}." >&2 + return 1 + fi; +} + +main() { + tarballName=$(teleportTarballName) + echo "Downloading from $${cdnBaseURL}/$${tarballName} and extracting teleport to $${tempDir} ..." + curl --show-error --fail --location $${cdnBaseURL}/$${tarballName} | tar xzf - -C $${tempDir} $${teleportFlavor}/teleport + + mkdir -p $${tempDir}/bin + mv $${tempDir}/$${teleportFlavor}/teleport $${tempDir}/bin/teleport + echo "> $${tempDir}/bin/teleport $${teleportArgs} $@" + sudo $${tempDir}/bin/teleport $${teleportArgs} $@ && echo $successMessage +} + +main $@ +EOF + } +} + +``` + ## teleport_login_rule | Name | Type | Required | Description | diff --git a/integrations/terraform/testlib/fixtures/installer_0_create.tf b/integrations/terraform/testlib/fixtures/installer_0_create.tf new file mode 100644 index 0000000000000..ac96dda77bab4 --- /dev/null +++ b/integrations/terraform/testlib/fixtures/installer_0_create.tf @@ -0,0 +1,15 @@ +resource "teleport_installer" "test" { + version = "v1" + metadata = { + name = "test" + labels = { + example = "yes" + } + } + + spec = { + script = <. + */ + +package testlib + +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 *TerraformSuiteOSS) TestInstaller() { + ctx, cancel := context.WithCancel(context.Background()) + s.T().Cleanup(cancel) + + checkInstallerDestroyed := func(state *terraform.State) error { + _, err := s.client.GetInstaller(ctx, "test") + if trace.IsNotFound(err) { + return nil + } + + return err + } + + name := "teleport_installer.test" + + resource.Test(s.T(), resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + CheckDestroy: checkInstallerDestroyed, + Steps: []resource.TestStep{ + { + Config: s.getFixture("installer_0_create.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "installer"), + resource.TestCheckResourceAttr(name, "version", "v1"), + resource.TestCheckResourceAttr(name, "spec.script", "[Install Teleport Script]\n"), + ), + }, + { + Config: s.getFixture("installer_0_create.tf"), + PlanOnly: true, + }, + { + Config: s.getFixture("installer_1_update.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "installer"), + resource.TestCheckResourceAttr(name, "version", "v1"), + resource.TestCheckResourceAttr(name, "spec.script", "[Updated Install Teleport Script]\n"), + ), + }, + { + Config: s.getFixture("installer_1_update.tf"), + PlanOnly: true, + }, + }, + }) +} diff --git a/integrations/terraform/testlib/main_test.go b/integrations/terraform/testlib/main_test.go index dddafa66de9df..2eb01406700c6 100644 --- a/integrations/terraform/testlib/main_test.go +++ b/integrations/terraform/testlib/main_test.go @@ -114,6 +114,7 @@ func (s *TerraformBaseSuite) SetupSuite() { types.NewRule("access_list", unrestricted), types.NewRule("node", unrestricted), types.NewRule("bot", unrestricted), + types.NewRule("installer", unrestricted), }, }, }) diff --git a/integrations/terraform/tfschema/types_terraform.go b/integrations/terraform/tfschema/types_terraform.go index 083c43f71859b..9ebf193718e7d 100644 --- a/integrations/terraform/tfschema/types_terraform.go +++ b/integrations/terraform/tfschema/types_terraform.go @@ -3281,6 +3281,86 @@ func GenSchemaTrustedClusterV2(ctx context.Context) (github_com_hashicorp_terraf }}, nil } +// GenSchemaInstallerV1 returns tfsdk.Schema definition for InstallerV1 +func GenSchemaInstallerV1(ctx context.Context) (github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema, github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics) { + return github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema{Attributes: map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "id": { + Computed: true, + Optional: false, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Required: false, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "kind": { + Computed: true, + Description: "Kind is the resource kind.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "metadata": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "description": { + Description: "Description is object description", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "expires": { + Description: "Expires is a global expiry time header can be set on any resource in the system.", + Optional: true, + Type: UseRFC3339Time(), + Validators: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributeValidator{MustTimeBeInFuture()}, + }, + "labels": { + Description: "Labels is a set of labels", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.MapType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "name": { + Description: "Name is an object name", + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.RequiresReplace()}, + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "namespace": { + Computed: true, + Description: "Namespace is object namespace. The field should be called \"namespace\" when it returns in Teleport 2.4.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "revision": { + Description: "Revision is an opaque identifier which tracks the versions of a resource over time. Clients should ignore and not alter its value but must return the revision in any updates of a resource.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Metadata is the resource metadata.", + Optional: true, + }, + "spec": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"script": { + Description: "Script represents the contents of a installer shell script", + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }}), + Description: "Spec is the resource spec.", + Required: true, + }, + "sub_kind": { + Description: "SubKind is an optional resource subkind. Currently unused for this resource.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "version": { + Description: "Version is the resource version.", + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + Validators: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributeValidator{UseVersionBetween(1, 1)}, + }, + }}, nil +} + // GenSchemaClusterMaintenanceConfigV1 returns tfsdk.Schema definition for ClusterMaintenanceConfigV1 func GenSchemaClusterMaintenanceConfigV1(ctx context.Context) (github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema, github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics) { return github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema{Attributes: map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ @@ -32933,6 +33013,551 @@ func CopyTrustedClusterV2ToTerraform(ctx context.Context, obj *github_com_gravit return diags } +// CopyInstallerV1FromTerraform copies contents of the source Terraform object into a target struct +func CopyInstallerV1FromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_types.InstallerV1) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { + var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics + { + a, ok := tf.Attrs["kind"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Kind = t + } + } + } + { + a, ok := tf.Attrs["sub_kind"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.SubKind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.SubKind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.SubKind = t + } + } + } + { + a, ok := tf.Attrs["version"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Version"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Version", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Version = t + } + } + } + { + a, ok := tf.Attrs["metadata"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Metadata = github_com_gravitational_teleport_api_types.Metadata{} + if !v.Null && !v.Unknown { + tf := v + obj := &obj.Metadata + { + a, ok := tf.Attrs["name"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Name"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Name = t + } + } + } + { + a, ok := tf.Attrs["namespace"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Namespace"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Namespace", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Namespace = t + } + } + } + { + a, ok := tf.Attrs["description"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Description"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Description", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Description = t + } + } + } + { + a, ok := tf.Attrs["labels"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Labels"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Labels", "github.com/hashicorp/terraform-plugin-framework/types.Map"}) + } else { + obj.Labels = make(map[string]string, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Labels", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Labels[k] = t + } + } + } + } + } + } + { + a, ok := tf.Attrs["expires"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Expires"}) + } else { + v, ok := a.(TimeValue) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Expires", "TimeValue"}) + } else { + var t *time.Time + if !v.Null && !v.Unknown { + c := time.Time(v.Value) + t = &c + } + obj.Expires = t + } + } + } + { + a, ok := tf.Attrs["revision"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Metadata.Revision"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Metadata.Revision", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Revision = t + } + } + } + } + } + } + } + { + a, ok := tf.Attrs["spec"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Spec"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Spec", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Spec = github_com_gravitational_teleport_api_types.InstallerSpecV1{} + if !v.Null && !v.Unknown { + tf := v + obj := &obj.Spec + { + a, ok := tf.Attrs["script"] + if !ok { + diags.Append(attrReadMissingDiag{"InstallerV1.Spec.Script"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"InstallerV1.Spec.Script", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Script = t + } + } + } + } + } + } + } + return diags +} + +// CopyInstallerV1ToTerraform copies contents of the source Terraform object into a target struct +func CopyInstallerV1ToTerraform(ctx context.Context, obj *github_com_gravitational_teleport_api_types.InstallerV1, tf *github_com_hashicorp_terraform_plugin_framework_types.Object) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { + var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics + tf.Null = false + tf.Unknown = false + if tf.Attrs == nil { + tf.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value) + } + { + t, ok := tf.AttrTypes["kind"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Kind"}) + } else { + v, ok := tf.Attrs["kind"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Kind) == "" + } + v.Value = string(obj.Kind) + v.Unknown = false + tf.Attrs["kind"] = v + } + } + { + t, ok := tf.AttrTypes["sub_kind"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.SubKind"}) + } else { + v, ok := tf.Attrs["sub_kind"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.SubKind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.SubKind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.SubKind) == "" + } + v.Value = string(obj.SubKind) + v.Unknown = false + tf.Attrs["sub_kind"] = v + } + } + { + t, ok := tf.AttrTypes["version"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Version"}) + } else { + v, ok := tf.Attrs["version"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Version", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Version", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Version) == "" + } + v.Value = string(obj.Version) + v.Unknown = false + tf.Attrs["version"] = v + } + } + { + a, ok := tf.AttrTypes["metadata"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["metadata"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + { + obj := obj.Metadata + tf := &v + { + t, ok := tf.AttrTypes["name"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Name"}) + } else { + v, ok := tf.Attrs["name"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Name", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Name) == "" + } + v.Value = string(obj.Name) + v.Unknown = false + tf.Attrs["name"] = v + } + } + { + t, ok := tf.AttrTypes["namespace"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Namespace"}) + } else { + v, ok := tf.Attrs["namespace"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Namespace", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Namespace", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Namespace) == "" + } + v.Value = string(obj.Namespace) + v.Unknown = false + tf.Attrs["namespace"] = v + } + } + { + t, ok := tf.AttrTypes["description"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Description"}) + } else { + v, ok := tf.Attrs["description"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Description", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Description", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Description) == "" + } + v.Value = string(obj.Description) + v.Unknown = false + tf.Attrs["description"] = v + } + } + { + a, ok := tf.AttrTypes["labels"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Labels"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.MapType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Labels", "github.com/hashicorp/terraform-plugin-framework/types.MapType"}) + } else { + c, ok := tf.Attrs["labels"].(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.Map{ + + ElemType: o.ElemType, + Elems: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Labels)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Labels)) + } + } + if obj.Labels != nil { + t := o.ElemType + for k, a := range obj.Labels { + v, ok := tf.Attrs["labels"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Labels", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Labels", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = false + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Labels) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["labels"] = c + } + } + } + { + t, ok := tf.AttrTypes["expires"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Expires"}) + } else { + v, ok := tf.Attrs["expires"].(TimeValue) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Expires", err}) + } + v, ok = i.(TimeValue) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Expires", "TimeValue"}) + } + v.Null = false + } + if obj.Expires == nil { + v.Null = true + } else { + v.Null = false + v.Value = time.Time(*obj.Expires) + } + v.Unknown = false + tf.Attrs["expires"] = v + } + } + { + t, ok := tf.AttrTypes["revision"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Metadata.Revision"}) + } else { + v, ok := tf.Attrs["revision"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Metadata.Revision", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Metadata.Revision", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Revision) == "" + } + v.Value = string(obj.Revision) + v.Unknown = false + tf.Attrs["revision"] = v + } + } + } + v.Unknown = false + tf.Attrs["metadata"] = v + } + } + } + { + a, ok := tf.AttrTypes["spec"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Spec"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Spec", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["spec"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + { + obj := obj.Spec + tf := &v + { + t, ok := tf.AttrTypes["script"] + if !ok { + diags.Append(attrWriteMissingDiag{"InstallerV1.Spec.Script"}) + } else { + v, ok := tf.Attrs["script"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"InstallerV1.Spec.Script", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"InstallerV1.Spec.Script", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Script) == "" + } + v.Value = string(obj.Script) + v.Unknown = false + tf.Attrs["script"] = v + } + } + } + v.Unknown = false + tf.Attrs["spec"] = v + } + } + } + return diags +} + // CopyClusterMaintenanceConfigV1FromTerraform copies contents of the source Terraform object into a target struct func CopyClusterMaintenanceConfigV1FromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_types.ClusterMaintenanceConfigV1) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics