From 826f83827436edd2a3036f4a4bcade0314b77244 Mon Sep 17 00:00:00 2001 From: Andrew Burke Date: Thu, 19 Sep 2024 12:15:17 -0700 Subject: [PATCH] Add SHU to terraform provider This change adds Terraform support for static host users. --- .../terraform-provider/data-sources.mdx | 1 + .../data-sources/static_host_user.mdx | 64 + .../terraform-provider/resources.mdx | 1 + .../resources/static_host_user.mdx | 91 ++ integrations/terraform/Makefile | 8 + .../teleport_static_host_user/resource.tf | 24 + integrations/terraform/gen/main.go | 28 + .../protoc-gen-terraform-statichostuser.yaml | 72 + .../data_source_teleport_static_host_user.go | 82 + integrations/terraform/provider/provider.go | 2 + .../resource_teleport_static_host_user.go | 318 ++++ .../fixtures/static_host_user_0_create.tf | 19 + .../fixtures/static_host_user_1_update.tf | 19 + .../testlib/static_host_user_test.go | 148 ++ .../userprovisioning/v2/custom_types.go | 25 + .../v2/statichostuser_terraform.go | 1407 +++++++++++++++++ lib/services/presets.go | 1 + 17 files changed, 2310 insertions(+) create mode 100644 docs/pages/reference/terraform-provider/data-sources/static_host_user.mdx create mode 100644 docs/pages/reference/terraform-provider/resources/static_host_user.mdx create mode 100644 integrations/terraform/examples/resources/teleport_static_host_user/resource.tf create mode 100644 integrations/terraform/protoc-gen-terraform-statichostuser.yaml create mode 100755 integrations/terraform/provider/data_source_teleport_static_host_user.go create mode 100755 integrations/terraform/provider/resource_teleport_static_host_user.go create mode 100644 integrations/terraform/testlib/fixtures/static_host_user_0_create.tf create mode 100644 integrations/terraform/testlib/fixtures/static_host_user_1_update.tf create mode 100644 integrations/terraform/testlib/static_host_user_test.go create mode 100644 integrations/terraform/tfschema/userprovisioning/v2/custom_types.go create mode 100644 integrations/terraform/tfschema/userprovisioning/v2/statichostuser_terraform.go diff --git a/docs/pages/reference/terraform-provider/data-sources.mdx b/docs/pages/reference/terraform-provider/data-sources.mdx index cc05856f6f547..6c7f82c16279a 100644 --- a/docs/pages/reference/terraform-provider/data-sources.mdx +++ b/docs/pages/reference/terraform-provider/data-sources.mdx @@ -29,6 +29,7 @@ The Teleport Terraform provider supports the following data-sources: - [`teleport_role`](./data-sources/role.mdx) - [`teleport_saml_connector`](./data-sources/saml_connector.mdx) - [`teleport_session_recording_config`](./data-sources/session_recording_config.mdx) + - [`teleport_static_host_user`](./data-sources/static_host_user.mdx) - [`teleport_trusted_cluster`](./data-sources/trusted_cluster.mdx) - [`teleport_trusted_device`](./data-sources/trusted_device.mdx) - [`teleport_user`](./data-sources/user.mdx) diff --git a/docs/pages/reference/terraform-provider/data-sources/static_host_user.mdx b/docs/pages/reference/terraform-provider/data-sources/static_host_user.mdx new file mode 100644 index 0000000000000..99219be614718 --- /dev/null +++ b/docs/pages/reference/terraform-provider/data-sources/static_host_user.mdx @@ -0,0 +1,64 @@ +--- +title: Reference for the teleport_static_host_user Terraform data-source +description: This page describes the supported values of the teleport_static_host_user data-source of the Teleport Terraform provider. +--- + +{/*Auto-generated file. Do not edit.*/} +{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} + + + + + +{/* schema generated by tfplugindocs */} +## Schema + +### Required + +- `metadata` (Attributes) metadata is resource metadata. (see [below for nested schema](#nested-schema-for-metadata)) +- `spec` (Attributes) spec is the static host user spec. (see [below for nested schema](#nested-schema-for-spec)) +- `version` (String) version is the resource version. It must be specified. Supported values are: `v2`. + +### Optional + +- `sub_kind` (String) sub_kind is an optional resource sub kind, used in some resources. + +### Nested Schema for `metadata` + +Required: + +- `name` (String) name is an object name. + +Optional: + +- `description` (String) description is object description. +- `expires` (String) +- `labels` (Map of String) labels is a set of labels. + + +### Nested Schema for `spec` + +Required: + +- `matchers` (Attributes List) (see [below for nested schema](#nested-schema-for-specmatchers)) + +### Nested Schema for `spec.matchers` + +Optional: + +- `default_shell` (String) default_shell is the new user's default shell +- `gid` (Number) gid is the new user's gid. +- `groups` (List of String) groups is a list of additional groups to add the user to. +- `node_labels` (Attributes List) node_labels is a map of node labels that will create a user from this resource. (see [below for nested schema](#nested-schema-for-specmatchersnode_labels)) +- `node_labels_expression` (String) node_labels_expression is a predicate expression to create a user from this resource. +- `sudoers` (List of String) sudoers is a list of sudoer entries to add. +- `take_ownership_if_user_exists` (Boolean) take_ownership_if_user_exists will take ownership of existing, unmanaged users +- `uid` (Number) uid is the new user's uid. + +### Nested Schema for `spec.matchers.node_labels` + +Required: + +- `name` (String) The name of the label. +- `values` (List of String) The values associated with the label. + diff --git a/docs/pages/reference/terraform-provider/resources.mdx b/docs/pages/reference/terraform-provider/resources.mdx index 01f9bc70a9fff..dd2640e926d22 100644 --- a/docs/pages/reference/terraform-provider/resources.mdx +++ b/docs/pages/reference/terraform-provider/resources.mdx @@ -31,6 +31,7 @@ The Teleport Terraform provider supports the following resources: - [`teleport_saml_connector`](./resources/saml_connector.mdx) - [`teleport_server`](./resources/server.mdx) - [`teleport_session_recording_config`](./resources/session_recording_config.mdx) + - [`teleport_static_host_user`](./resources/static_host_user.mdx) - [`teleport_trusted_cluster`](./resources/trusted_cluster.mdx) - [`teleport_trusted_device`](./resources/trusted_device.mdx) - [`teleport_user`](./resources/user.mdx) diff --git a/docs/pages/reference/terraform-provider/resources/static_host_user.mdx b/docs/pages/reference/terraform-provider/resources/static_host_user.mdx new file mode 100644 index 0000000000000..00cebadd20e08 --- /dev/null +++ b/docs/pages/reference/terraform-provider/resources/static_host_user.mdx @@ -0,0 +1,91 @@ +--- +title: Reference for the teleport_static_host_user Terraform resource +description: This page describes the supported values of the teleport_static_host_user resource of the Teleport Terraform provider. +--- + +{/*Auto-generated file. Do not edit.*/} +{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} + + + +## Example Usage + +```hcl +resource "teleport_static_host_user" "test" { + version = "v2" + metadata = { + name = "test" + } + spec = { + matchers = [ + { + node_labels = [ + { + name = "foo" + values = ["bar"] + } + ] + node_labels_expression = "labels.foo == \"bar\"" + groups = ["foo", "bar"] + sudoers = ["abcd1234"] + uid = 1234 + gid = 1234 + default_shell = "/bin/bash" + } + ] + } +} +``` + +{/* schema generated by tfplugindocs */} +## Schema + +### Required + +- `metadata` (Attributes) metadata is resource metadata. (see [below for nested schema](#nested-schema-for-metadata)) +- `spec` (Attributes) spec is the static host user spec. (see [below for nested schema](#nested-schema-for-spec)) +- `version` (String) version is the resource version. It must be specified. Supported values are: `v2`. + +### Optional + +- `sub_kind` (String) sub_kind is an optional resource sub kind, used in some resources. + +### Nested Schema for `metadata` + +Required: + +- `name` (String) name is an object name. + +Optional: + +- `description` (String) description is object description. +- `expires` (String) +- `labels` (Map of String) labels is a set of labels. + + +### Nested Schema for `spec` + +Required: + +- `matchers` (Attributes List) (see [below for nested schema](#nested-schema-for-specmatchers)) + +### Nested Schema for `spec.matchers` + +Optional: + +- `default_shell` (String) default_shell is the new user's default shell +- `gid` (Number) gid is the new user's gid. +- `groups` (List of String) groups is a list of additional groups to add the user to. +- `node_labels` (Attributes List) node_labels is a map of node labels that will create a user from this resource. (see [below for nested schema](#nested-schema-for-specmatchersnode_labels)) +- `node_labels_expression` (String) node_labels_expression is a predicate expression to create a user from this resource. +- `sudoers` (List of String) sudoers is a list of sudoer entries to add. +- `take_ownership_if_user_exists` (Boolean) take_ownership_if_user_exists will take ownership of existing, unmanaged users +- `uid` (Number) uid is the new user's uid. + +### Nested Schema for `spec.matchers.node_labels` + +Required: + +- `name` (String) The name of the label. +- `values` (List of String) The values associated with the label. + diff --git a/integrations/terraform/Makefile b/integrations/terraform/Makefile index 517b915e848f2..cb6dcd61d958d 100644 --- a/integrations/terraform/Makefile +++ b/integrations/terraform/Makefile @@ -106,9 +106,17 @@ endif --terraform_out=config=protoc-gen-terraform-accessmonitoringrules.yaml:./tfschema \ teleport/accessmonitoringrules/v1/access_monitoring_rules.proto + @protoc \ + -I=../../api/proto \ + -I=$(PROTOBUF_MOD_PATH) \ + --plugin=$(GENTERRAFORMPATH)/protoc-gen-terraform \ + --terraform_out=config=protoc-gen-terraform-statichostuser.yaml:./tfschema \ + teleport/userprovisioning/v2/statichostuser.proto + mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1/loginrule_terraform.go ./tfschema/loginrule/v1/ mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1/accesslist_terraform.go ./tfschema/accesslist/v1/ mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_terraform.go ./tfschema/accessmonitoringrules/v1/ + mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_terraform.go ./tfschema/userprovisioning/v2/ mv ./tfschema/github.com/gravitational/teleport/api/types/device_terraform.go ./tfschema/devicetrust/v1/ rm -r ./tfschema/github.com/ @go run ./gen/main.go diff --git a/integrations/terraform/examples/resources/teleport_static_host_user/resource.tf b/integrations/terraform/examples/resources/teleport_static_host_user/resource.tf new file mode 100644 index 0000000000000..192c97116375b --- /dev/null +++ b/integrations/terraform/examples/resources/teleport_static_host_user/resource.tf @@ -0,0 +1,24 @@ +resource "teleport_static_host_user" "test" { + version = "v2" + metadata = { + name = "test" + } + spec = { + matchers = [ + { + node_labels = [ + { + name = "foo" + values = ["bar"] + } + ] + node_labels_expression = "labels.foo == \"bar\"" + groups = ["foo", "bar"] + sudoers = ["abcd1234"] + uid = 1234 + gid = 1234 + default_shell = "/bin/bash" + } + ] + } +} \ No newline at end of file diff --git a/integrations/terraform/gen/main.go b/integrations/terraform/gen/main.go index c4981b5ca8bb8..2252399cd5cc7 100644 --- a/integrations/terraform/gen/main.go +++ b/integrations/terraform/gen/main.go @@ -476,6 +476,32 @@ var ( ExtraImports: []string{"apitypes \"github.com/gravitational/teleport/api/types\""}, ForceSetKind: "apitypes.KindAccessMonitoringRule", } + + staticHostUser = payload{ + Name: "StaticHostUser", + TypeName: "StaticHostUser", + VarName: "staticHostUser", + GetMethod: "StaticHostUserClient().GetStaticHostUser", + CreateMethod: "StaticHostUserClient().CreateStaticHostUser", + UpsertMethodArity: 2, + UpdateMethod: "StaticHostUserClient().UpsertStaticHostUser", + DeleteMethod: "StaticHostUserClient().DeleteStaticHostUser", + ID: "staticHostUser.Metadata.Name", + Kind: "static_host_user", + HasStaticID: false, + ProtoPackage: "userprovisioningv2", + ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2", + SchemaPackage: "schemav1", + SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/userprovisioning/v2", + TerraformResourceType: "teleport_static_host_user", + // Since [RFD 153](https://github.com/gravitational/teleport/blob/master/rfd/0153-resource-guidelines.md) + // resources are plain structs + IsPlainStruct: true, + // As 153-style resources don't have CheckAndSetDefaults, we must set the Kind manually. + // We import the package containing kinds, then use ForceSetKind. + ExtraImports: []string{"apitypes \"github.com/gravitational/teleport/api/types\""}, + ForceSetKind: "apitypes.KindStaticHostUser", + } ) func main() { @@ -523,6 +549,8 @@ func genTFSchema() { generateDataSource(installer, pluralDataSource) generateResource(accessMonitoringRule, pluralResource) generateDataSource(accessMonitoringRule, pluralDataSource) + generateResource(staticHostUser, pluralResource) + generateDataSource(staticHostUser, pluralDataSource) } func generateResource(p payload, tpl string) { diff --git a/integrations/terraform/protoc-gen-terraform-statichostuser.yaml b/integrations/terraform/protoc-gen-terraform-statichostuser.yaml new file mode 100644 index 0000000000000..f2e2330394307 --- /dev/null +++ b/integrations/terraform/protoc-gen-terraform-statichostuser.yaml @@ -0,0 +1,72 @@ +--- +target_package_name: "v2" +default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" +duration_custom_type: Duration +use_state_for_unknown_by_default: true + +# Top-level type names to export +types: + - "StaticHostUser" + +# These import paths were not being automatically picked up by +# protoc-gen-terraform without these overrides +import_path_overrides: + "types": "github.com/gravitational/teleport/api/types" + "wrappers": "github.com/gravitational/teleport/api/types/wrappers" + "durationpb": "google.golang.org/protobuf/types/known/durationpb" + "timestamppb": "google.golang.org/protobuf/types/known/timestamppb" + "v1": "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + "v11": "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" + + +# id field is required for integration tests. It is not used by provider. +# We have to add it manually (might be removed in the future versions). +injected_fields: + StaticHostUser: + - name: id + type: github.com/hashicorp/terraform-plugin-framework/types.StringType + computed: true + plan_modifiers: + - "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()" + +# These fields will be excluded +exclude_fields: + # Metadata (we id resources by name on our side) + - "StaticHostUser.metadata.id" + +# These fields will be marked as Computed: true +computed_fields: + # Metadata + - "StaticHostUser.metadata.namespace" + - "StaticHostUser.kind" + +# These fields will be marked as Required: true +required_fields: + - "StaticHostUser.version" + - "StaticHostUser.metadata" + - "StaticHostUser.metadata.name" + - "StaticHostUser.spec" + - "StaticHostUser.spec.matchers" + - "StaticHostUser.spec.matchers.node_labels.name" + - "StaticHostUser.spec.matchers.node_labels.values" + +plan_modifiers: + # Force to recreate resource if it's name changes + Metadata.name: + - "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()" + +# This must be defined for the generator to be happy, but in reality all time +# fields are overridden (because the protobuf timestamps contain locks and the +# linter gets mad if we use raw structs instead of pointers). +time_type: + type: "PlaceholderType" +duration_type: + type: "PlaceholderType" + +validators: + # Expires must be in the future + Metadata.expires: + - github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture() + +custom_types: + "StaticHostUser.metadata.expires": Timestamp \ No newline at end of file diff --git a/integrations/terraform/provider/data_source_teleport_static_host_user.go b/integrations/terraform/provider/data_source_teleport_static_host_user.go new file mode 100755 index 0000000000000..f8b59df73c963 --- /dev/null +++ b/integrations/terraform/provider/data_source_teleport_static_host_user.go @@ -0,0 +1,82 @@ +// 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 provider + +import ( + "context" + + + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/userprovisioning/v2" +) + +// dataSourceTeleportStaticHostUserType is the data source metadata type +type dataSourceTeleportStaticHostUserType struct{} + +// dataSourceTeleportStaticHostUser is the resource +type dataSourceTeleportStaticHostUser struct { + p Provider +} + +// GetSchema returns the data source schema +func (r dataSourceTeleportStaticHostUserType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaStaticHostUser(ctx) +} + +// NewDataSource creates the empty data source +func (r dataSourceTeleportStaticHostUserType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) { + return dataSourceTeleportStaticHostUser{ + p: *(p.(*Provider)), + }, nil +} + +// Read reads teleport StaticHostUser +func (r dataSourceTeleportStaticHostUser) 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 + } + + staticHostUserI, err := r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, id.Value) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + + var state types.Object + staticHostUser := staticHostUserI + + diags = schemav1.CopyStaticHostUserToTerraform(ctx, staticHostUser, &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 37c6eefd9e3c4..dfc0d9b9a14c3 100644 --- a/integrations/terraform/provider/provider.go +++ b/integrations/terraform/provider/provider.go @@ -502,6 +502,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp "teleport_server": resourceTeleportServerType{}, "teleport_installer": resourceTeleportInstallerType{}, "teleport_access_monitoring_rule": resourceTeleportAccessMonitoringRuleType{}, + "teleport_static_host_user": resourceTeleportStaticHostUserType{}, }, nil } @@ -527,6 +528,7 @@ func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourc "teleport_access_list": dataSourceTeleportAccessListType{}, "teleport_installer": dataSourceTeleportInstallerType{}, "teleport_access_monitoring_rule": dataSourceTeleportAccessMonitoringRuleType{}, + "teleport_static_host_user": dataSourceTeleportStaticHostUserType{}, }, nil } diff --git a/integrations/terraform/provider/resource_teleport_static_host_user.go b/integrations/terraform/provider/resource_teleport_static_host_user.go new file mode 100755 index 0000000000000..61acd2e81fb26 --- /dev/null +++ b/integrations/terraform/provider/resource_teleport_static_host_user.go @@ -0,0 +1,318 @@ +// 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 provider + +import ( + "context" + "fmt" + apitypes "github.com/gravitational/teleport/api/types" + + userprovisioningv2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + + "github.com/gravitational/teleport/integrations/lib/backoff" + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jonboulle/clockwork" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/userprovisioning/v2" +) + +// resourceTeleportStaticHostUserType is the resource metadata type +type resourceTeleportStaticHostUserType struct{} + +// resourceTeleportStaticHostUser is the resource +type resourceTeleportStaticHostUser struct { + p Provider +} + +// GetSchema returns the resource schema +func (r resourceTeleportStaticHostUserType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaStaticHostUser(ctx) +} + +// NewResource creates the empty resource +func (r resourceTeleportStaticHostUserType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) { + return resourceTeleportStaticHostUser{ + p: *(p.(*Provider)), + }, nil +} + +// Create creates the StaticHostUser +func (r resourceTeleportStaticHostUser) 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 + } + + staticHostUser := &userprovisioningv2.StaticHostUser{} + diags = schemav1.CopyStaticHostUserFromTerraform(ctx, plan, staticHostUser) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + + staticHostUserResource := staticHostUser + + staticHostUserResource.Kind = apitypes.KindStaticHostUser + + id := staticHostUserResource.Metadata.Name + + _, err = r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, id) + if !trace.IsNotFound(err) { + if err == nil { + existErr := fmt.Sprintf("StaticHostUser exists in Teleport. Either remove it (tctl rm static_host_user/%v)"+ + " or import it to the existing state (terraform import teleport_static_host_user.%v %v)", id, id, id) + + resp.Diagnostics.Append(diagFromErr("StaticHostUser exists in Teleport", trace.Errorf(existErr))) + return + } + + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + + _, err = r.p.Client.StaticHostUserClient().CreateStaticHostUser(ctx, staticHostUserResource) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error creating StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + var staticHostUserI *userprovisioningv2.StaticHostUser + tries := 0 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + staticHostUserI, err = r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, id) + if trace.IsNotFound(err) { + if bErr := backoff.Do(ctx); bErr != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(bErr), "static_host_user")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading StaticHostUser (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "static_host_user") + } + continue + } + break + } + + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + + staticHostUserResource = staticHostUserI + + staticHostUser = staticHostUserResource + + diags = schemav1.CopyStaticHostUserToTerraform(ctx, staticHostUser, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + plan.Attrs["id"] = types.String{Value: staticHostUser.Metadata.Name} + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read reads teleport StaticHostUser +func (r resourceTeleportStaticHostUser) 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 + } + + staticHostUserI, err := r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, id.Value) + if trace.IsNotFound(err) { + resp.State.RemoveResource(ctx) + return + } + + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + staticHostUser := staticHostUserI + diags = schemav1.CopyStaticHostUserToTerraform(ctx, staticHostUser, &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 StaticHostUser +func (r resourceTeleportStaticHostUser) 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 + } + + staticHostUser := &userprovisioningv2.StaticHostUser{} + diags = schemav1.CopyStaticHostUserFromTerraform(ctx, plan, staticHostUser) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + staticHostUserResource := staticHostUser + + + + name := staticHostUserResource.Metadata.Name + + staticHostUserBefore, err := r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, name) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", err, "static_host_user")) + return + } + + _, err = r.p.Client.StaticHostUserClient().UpsertStaticHostUser(ctx, staticHostUserResource) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error updating StaticHostUser", err, "static_host_user")) + return + } + var staticHostUserI *userprovisioningv2.StaticHostUser + + tries := 0 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + staticHostUserI, err = r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, name) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", err, "static_host_user")) + return + } + if staticHostUserBefore.GetMetadata().Revision != staticHostUserI.GetMetadata().Revision || false { + break + } + + if err := backoff.Do(ctx); err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading StaticHostUser (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "static_host_user") + return + } + } + + staticHostUserResource = staticHostUserI + + diags = schemav1.CopyStaticHostUserToTerraform(ctx, staticHostUser, &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 StaticHostUser +func (r resourceTeleportStaticHostUser) 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.StaticHostUserClient().DeleteStaticHostUser(ctx, id.Value) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error deleting StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + + resp.State.RemoveResource(ctx) +} + +// ImportState imports StaticHostUser state +func (r resourceTeleportStaticHostUser) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) { + staticHostUser, err := r.p.Client.StaticHostUserClient().GetStaticHostUser(ctx, req.ID) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading StaticHostUser", trace.Wrap(err), "static_host_user")) + return + } + + staticHostUserResource := staticHostUser + + + var state types.Object + + diags := resp.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = schemav1.CopyStaticHostUserToTerraform(ctx, staticHostUserResource, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + id := staticHostUser.Metadata.Name + + 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/testlib/fixtures/static_host_user_0_create.tf b/integrations/terraform/testlib/fixtures/static_host_user_0_create.tf new file mode 100644 index 0000000000000..2d36081e1799f --- /dev/null +++ b/integrations/terraform/testlib/fixtures/static_host_user_0_create.tf @@ -0,0 +1,19 @@ +resource "teleport_static_host_user" "test" { + version = "v2" + metadata = { + name = "test" + } + spec = { + matchers = [ + { + node_labels = [ + { + name = "foo" + values = ["bar"] + } + ] + groups = ["foo", "bar"] + } + ] + } +} \ No newline at end of file diff --git a/integrations/terraform/testlib/fixtures/static_host_user_1_update.tf b/integrations/terraform/testlib/fixtures/static_host_user_1_update.tf new file mode 100644 index 0000000000000..a7221c25c2645 --- /dev/null +++ b/integrations/terraform/testlib/fixtures/static_host_user_1_update.tf @@ -0,0 +1,19 @@ +resource "teleport_static_host_user" "test" { + version = "v2" + metadata = { + name = "test" + } + spec = { + matchers = [ + { + node_labels = [ + { + name = "baz" + values = ["quux"] + } + ] + groups = ["baz", "quux"] + } + ] + } +} \ No newline at end of file diff --git a/integrations/terraform/testlib/static_host_user_test.go b/integrations/terraform/testlib/static_host_user_test.go new file mode 100644 index 0000000000000..2ca096d6a1058 --- /dev/null +++ b/integrations/terraform/testlib/static_host_user_test.go @@ -0,0 +1,148 @@ +// Teleport +// Copyright (C) 2024 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 . + +package testlib + +import ( + "context" + "fmt" + "time" + + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/stretchr/testify/require" + + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + labelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" + userprovisioningv2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + "github.com/gravitational/teleport/api/types" +) + +func (s *TerraformSuiteOSS) TestStaticHostUser() { + t := s.T() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + checkDestroyed := func(state *terraform.State) error { + _, err := s.client.StaticHostUserClient().GetStaticHostUser(ctx, "test") + if trace.IsNotFound(err) { + return nil + } + return trace.Errorf("expected not found, actual: %v", err) + } + + name := "teleport_static_host_user.test" + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + CheckDestroy: checkDestroyed, + IsUnitTest: true, + Steps: []resource.TestStep{ + { + Config: s.getFixture("static_host_user_0_create.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "static_host_user"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.node_labels.0.name", "foo"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.node_labels.0.values.0", "bar"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.groups.0", "foo"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.groups.1", "bar"), + ), + }, + { + Config: s.getFixture("static_host_user_0_create.tf"), + PlanOnly: true, + }, + { + Config: s.getFixture("static_host_user_1_update.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "static_host_user"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.node_labels.0.name", "baz"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.node_labels.0.values.0", "quux"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.groups.0", "baz"), + resource.TestCheckResourceAttr(name, "spec.matchers.0.groups.1", "quux"), + ), + }, + { + Config: s.getFixture("static_host_user_1_update.tf"), + PlanOnly: true, + }, + }, + }) +} + +func (s *TerraformSuiteOSS) TestImportStaticHostUser() { + t := s.T() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + r := "teleport_static_host_user" + id := "test_import" + name := r + "." + id + + labels := []*labelv1.Label{ + { + Name: "foo", + Values: []string{"bar"}, + }, + } + groups := []string{"foo", "bar"} + + shu := &userprovisioningv2.StaticHostUser{ + Metadata: &v1.Metadata{ + Name: id, + }, + Kind: types.KindStaticHostUser, + Version: types.V2, + Spec: &userprovisioningv2.StaticHostUserSpec{ + Matchers: []*userprovisioningv2.Matcher{ + { + NodeLabels: labels, + Groups: groups, + }, + }, + }, + } + shu, err := s.client.StaticHostUserClient().CreateStaticHostUser(ctx, shu) + require.NoError(t, err) + + require.Eventually(t, func() bool { + _, err := s.client.StaticHostUserClient().GetStaticHostUser(ctx, shu.GetMetadata().Name) + return err == nil + }, 5*time.Second, time.Second) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + IsUnitTest: true, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf("%s\nresource %q %q { }", s.terraformConfig, r, id), + ResourceName: name, + ImportState: true, + ImportStateId: id, + ImportStateCheck: func(state []*terraform.InstanceState) error { + require.Equal(t, types.KindStaticHostUser, state[0].Attributes["kind"]) + require.Equal(t, labels[0].Name, state[0].Attributes["spec.matchers.0.node_labels.0.name"]) + require.Equal(t, labels[0].Values[0], state[0].Attributes["spec.matchers.0.node_labels.0.values.0"]) + require.Equal(t, groups[0], state[0].Attributes["spec.matchers.0.groups.0"]) + require.Equal(t, groups[1], state[0].Attributes["spec.matchers.0.groups.1"]) + + return nil + }, + }, + }, + }) +} diff --git a/integrations/terraform/tfschema/userprovisioning/v2/custom_types.go b/integrations/terraform/tfschema/userprovisioning/v2/custom_types.go new file mode 100644 index 0000000000000..333531081e4e5 --- /dev/null +++ b/integrations/terraform/tfschema/userprovisioning/v2/custom_types.go @@ -0,0 +1,25 @@ +// Teleport +// Copyright (C) 2024 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 . + +package v2 + +import "github.com/gravitational/teleport/integrations/terraform/tfschema/resource153" + +var ( + GenSchemaTimestamp = resource153.GenSchemaTimestamp + CopyToTimestamp = resource153.CopyToTimestamp + CopyFromTimestamp = resource153.CopyFromTimestamp +) diff --git a/integrations/terraform/tfschema/userprovisioning/v2/statichostuser_terraform.go b/integrations/terraform/tfschema/userprovisioning/v2/statichostuser_terraform.go new file mode 100644 index 0000000000000..e327611eb1849 --- /dev/null +++ b/integrations/terraform/tfschema/userprovisioning/v2/statichostuser_terraform.go @@ -0,0 +1,1407 @@ +/* +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. +*/ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: teleport/userprovisioning/v2/statichostuser.proto + +package v2 + +import ( + context "context" + fmt "fmt" + math "math" + + proto "github.com/gogo/protobuf/proto" + _ "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + github_com_gravitational_teleport_api_gen_proto_go_teleport_header_v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + _ "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" + github_com_gravitational_teleport_api_gen_proto_go_teleport_label_v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" + github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + github_com_hashicorp_terraform_plugin_framework_attr "github.com/hashicorp/terraform-plugin-framework/attr" + github_com_hashicorp_terraform_plugin_framework_diag "github.com/hashicorp/terraform-plugin-framework/diag" + github_com_hashicorp_terraform_plugin_framework_tfsdk "github.com/hashicorp/terraform-plugin-framework/tfsdk" + github_com_hashicorp_terraform_plugin_framework_types "github.com/hashicorp/terraform-plugin-framework/types" + github_com_hashicorp_terraform_plugin_go_tftypes "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// GenSchemaStaticHostUser returns tfsdk.Schema definition for StaticHostUser +func GenSchemaStaticHostUser(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 a 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": GenSchemaTimestamp(ctx), + "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 resource metadata.", + Required: true, + }, + "spec": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"matchers": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "default_shell": { + Description: "default_shell is the new user's default shell", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "gid": { + Description: "gid is the new user's gid.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.Int64Type, + }, + "groups": { + Description: "groups is a list of additional groups to add the user to.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "node_labels": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "name": { + Description: "The name of the label.", + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "values": { + Description: "The values associated with the label.", + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + }), + Description: "node_labels is a map of node labels that will create a user from this resource.", + Optional: true, + }, + "node_labels_expression": { + Description: "node_labels_expression is a predicate expression to create a user from this resource.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "sudoers": { + Description: "sudoers is a list of sudoer entries to add.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "take_ownership_if_user_exists": { + Description: "take_ownership_if_user_exists will take ownership of existing, unmanaged users", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.BoolType, + }, + "uid": { + Description: "uid is the new user's uid.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.Int64Type, + }, + }), + Description: "", + Required: true, + }}), + Description: "spec is the static host user spec.", + Required: true, + }, + "sub_kind": { + Description: "sub_kind is an optional resource sub kind, used in some resources.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "version": { + Description: "version is the resource version. It must be specified. Supported values are: `v2`.", + Required: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }}, nil +} + +// CopyStaticHostUserFromTerraform copies contents of the source Terraform object into a target struct +func CopyStaticHostUserFromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.StaticHostUser) 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{"StaticHostUser.kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.sub_kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.sub_kind", "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{"StaticHostUser.version"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.metadata", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Metadata = nil + if !v.Null && !v.Unknown { + tf := v + obj.Metadata = &github_com_gravitational_teleport_api_gen_proto_go_teleport_header_v1.Metadata{} + obj := obj.Metadata + { + a, ok := tf.Attrs["name"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.metadata.name"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.namespace"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.description"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.labels"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.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{"StaticHostUser.metadata.expires"}) + } + CopyFromTimestamp(diags, a, &obj.Expires) + } + { + a, ok := tf.Attrs["revision"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.metadata.revision"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.spec"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Spec = nil + if !v.Null && !v.Unknown { + tf := v + obj.Spec = &github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.StaticHostUserSpec{} + obj := obj.Spec + { + a, ok := tf.Attrs["matchers"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Matchers = make([]*github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.Matcher, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers", "github_com_hashicorp_terraform_plugin_framework_types.Object"}) + } else { + var t *github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.Matcher + if !v.Null && !v.Unknown { + tf := v + t = &github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.Matcher{} + obj := t + { + a, ok := tf.Attrs["node_labels"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.node_labels"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.NodeLabels = make([]*github_com_gravitational_teleport_api_gen_proto_go_teleport_label_v1.Label, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels", "github_com_hashicorp_terraform_plugin_framework_types.Object"}) + } else { + var t *github_com_gravitational_teleport_api_gen_proto_go_teleport_label_v1.Label + if !v.Null && !v.Unknown { + tf := v + t = &github_com_gravitational_teleport_api_gen_proto_go_teleport_label_v1.Label{} + obj := t + { + a, ok := tf.Attrs["name"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.node_labels.name"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels.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["values"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.node_labels.values"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels.values", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Values = make([]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{"StaticHostUser.spec.matchers.node_labels.values", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Values[k] = t + } + } + } + } + } + } + } + obj.NodeLabels[k] = t + } + } + } + } + } + } + { + a, ok := tf.Attrs["node_labels_expression"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.node_labels_expression"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels_expression", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.NodeLabelsExpression = t + } + } + } + { + a, ok := tf.Attrs["groups"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.groups"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.groups", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Groups = make([]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{"StaticHostUser.spec.matchers.groups", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Groups[k] = t + } + } + } + } + } + } + { + a, ok := tf.Attrs["sudoers"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.sudoers"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.sudoers", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Sudoers = make([]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{"StaticHostUser.spec.matchers.sudoers", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Sudoers[k] = t + } + } + } + } + } + } + { + a, ok := tf.Attrs["uid"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.uid"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Int64) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.uid", "github.com/hashicorp/terraform-plugin-framework/types.Int64"}) + } else { + var t int64 + if !v.Null && !v.Unknown { + t = int64(v.Value) + } + obj.Uid = t + } + } + } + { + a, ok := tf.Attrs["gid"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.gid"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Int64) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.gid", "github.com/hashicorp/terraform-plugin-framework/types.Int64"}) + } else { + var t int64 + if !v.Null && !v.Unknown { + t = int64(v.Value) + } + obj.Gid = t + } + } + } + { + a, ok := tf.Attrs["default_shell"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.default_shell"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.default_shell", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.DefaultShell = t + } + } + } + { + a, ok := tf.Attrs["take_ownership_if_user_exists"] + if !ok { + diags.Append(attrReadMissingDiag{"StaticHostUser.spec.matchers.take_ownership_if_user_exists"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Bool) + if !ok { + diags.Append(attrReadConversionFailureDiag{"StaticHostUser.spec.matchers.take_ownership_if_user_exists", "github.com/hashicorp/terraform-plugin-framework/types.Bool"}) + } else { + var t bool + if !v.Null && !v.Unknown { + t = bool(v.Value) + } + obj.TakeOwnershipIfUserExists = t + } + } + } + } + obj.Matchers[k] = t + } + } + } + } + } + } + } + } + } + } + return diags +} + +// CopyStaticHostUserToTerraform copies contents of the source Terraform object into a target struct +func CopyStaticHostUserToTerraform(ctx context.Context, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_userprovisioning_v2.StaticHostUser, 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{"StaticHostUser.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{"StaticHostUser.kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.sub_kind"}) + } 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{"StaticHostUser.sub_kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.sub_kind", "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{"StaticHostUser.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{"StaticHostUser.version", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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)) + } + } + if obj.Metadata == nil { + v.Null = true + } else { + obj := obj.Metadata + tf := &v + { + t, ok := tf.AttrTypes["name"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.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{"StaticHostUser.metadata.name", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.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{"StaticHostUser.metadata.namespace", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.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{"StaticHostUser.metadata.description", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.labels"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.MapType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.labels", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.metadata.expires"}) + } else { + v := CopyToTimestamp(diags, obj.Expires, t, tf.Attrs["expires"]) + tf.Attrs["expires"] = v + } + } + { + t, ok := tf.AttrTypes["revision"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.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{"StaticHostUser.metadata.revision", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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{"StaticHostUser.spec"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.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)) + } + } + if obj.Spec == nil { + v.Null = true + } else { + obj := obj.Spec + tf := &v + { + a, ok := tf.AttrTypes["matchers"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["matchers"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Matchers)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Matchers)) + } + } + if obj.Matchers != nil { + o := o.ElemType.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if len(obj.Matchers) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Matchers)) + } + for k, a := range obj.Matchers { + v, ok := tf.Attrs["matchers"].(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)) + } + } + if a == nil { + v.Null = true + } else { + obj := a + tf := &v + { + a, ok := tf.AttrTypes["node_labels"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.node_labels"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["node_labels"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.NodeLabels)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.NodeLabels)) + } + } + if obj.NodeLabels != nil { + o := o.ElemType.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if len(obj.NodeLabels) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.NodeLabels)) + } + for k, a := range obj.NodeLabels { + v, ok := tf.Attrs["node_labels"].(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)) + } + } + if a == nil { + v.Null = true + } else { + obj := a + tf := &v + { + t, ok := tf.AttrTypes["name"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.node_labels.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{"StaticHostUser.spec.matchers.node_labels.name", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels.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 + } + } + { + a, ok := tf.AttrTypes["values"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.node_labels.values"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels.values", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["values"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Values)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Values)) + } + } + if obj.Values != nil { + t := o.ElemType + if len(obj.Values) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Values)) + } + for k, a := range obj.Values { + v, ok := tf.Attrs["values"].(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{"StaticHostUser.spec.matchers.node_labels.values", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels.values", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Values) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["values"] = c + } + } + } + } + v.Unknown = false + c.Elems[k] = v + } + if len(obj.NodeLabels) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["node_labels"] = c + } + } + } + { + t, ok := tf.AttrTypes["node_labels_expression"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.node_labels_expression"}) + } else { + v, ok := tf.Attrs["node_labels_expression"].(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{"StaticHostUser.spec.matchers.node_labels_expression", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.node_labels_expression", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.NodeLabelsExpression) == "" + } + v.Value = string(obj.NodeLabelsExpression) + v.Unknown = false + tf.Attrs["node_labels_expression"] = v + } + } + { + a, ok := tf.AttrTypes["groups"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.groups"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.groups", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["groups"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Groups)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Groups)) + } + } + if obj.Groups != nil { + t := o.ElemType + if len(obj.Groups) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Groups)) + } + for k, a := range obj.Groups { + v, ok := tf.Attrs["groups"].(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{"StaticHostUser.spec.matchers.groups", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.groups", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Groups) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["groups"] = c + } + } + } + { + a, ok := tf.AttrTypes["sudoers"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.sudoers"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.sudoers", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["sudoers"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Sudoers)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Sudoers)) + } + } + if obj.Sudoers != nil { + t := o.ElemType + if len(obj.Sudoers) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Sudoers)) + } + for k, a := range obj.Sudoers { + v, ok := tf.Attrs["sudoers"].(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{"StaticHostUser.spec.matchers.sudoers", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.sudoers", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Sudoers) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["sudoers"] = c + } + } + } + { + t, ok := tf.AttrTypes["uid"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.uid"}) + } else { + v, ok := tf.Attrs["uid"].(github_com_hashicorp_terraform_plugin_framework_types.Int64) + 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{"StaticHostUser.spec.matchers.uid", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.Int64) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.uid", "github.com/hashicorp/terraform-plugin-framework/types.Int64"}) + } + v.Null = int64(obj.Uid) == 0 + } + v.Value = int64(obj.Uid) + v.Unknown = false + tf.Attrs["uid"] = v + } + } + { + t, ok := tf.AttrTypes["gid"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.gid"}) + } else { + v, ok := tf.Attrs["gid"].(github_com_hashicorp_terraform_plugin_framework_types.Int64) + 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{"StaticHostUser.spec.matchers.gid", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.Int64) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.gid", "github.com/hashicorp/terraform-plugin-framework/types.Int64"}) + } + v.Null = int64(obj.Gid) == 0 + } + v.Value = int64(obj.Gid) + v.Unknown = false + tf.Attrs["gid"] = v + } + } + { + t, ok := tf.AttrTypes["default_shell"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.default_shell"}) + } else { + v, ok := tf.Attrs["default_shell"].(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{"StaticHostUser.spec.matchers.default_shell", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.default_shell", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.DefaultShell) == "" + } + v.Value = string(obj.DefaultShell) + v.Unknown = false + tf.Attrs["default_shell"] = v + } + } + { + t, ok := tf.AttrTypes["take_ownership_if_user_exists"] + if !ok { + diags.Append(attrWriteMissingDiag{"StaticHostUser.spec.matchers.take_ownership_if_user_exists"}) + } else { + v, ok := tf.Attrs["take_ownership_if_user_exists"].(github_com_hashicorp_terraform_plugin_framework_types.Bool) + 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{"StaticHostUser.spec.matchers.take_ownership_if_user_exists", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.Bool) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"StaticHostUser.spec.matchers.take_ownership_if_user_exists", "github.com/hashicorp/terraform-plugin-framework/types.Bool"}) + } + v.Null = bool(obj.TakeOwnershipIfUserExists) == false + } + v.Value = bool(obj.TakeOwnershipIfUserExists) + v.Unknown = false + tf.Attrs["take_ownership_if_user_exists"] = v + } + } + } + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Matchers) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["matchers"] = c + } + } + } + } + v.Unknown = false + tf.Attrs["spec"] = v + } + } + } + return diags +} + +// attrReadMissingDiag represents diagnostic message on an attribute missing in the source object +type attrReadMissingDiag struct { + Path string +} + +func (d attrReadMissingDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrReadMissingDiag) Summary() string { + return "Error reading from Terraform object" +} + +func (d attrReadMissingDiag) Detail() string { + return fmt.Sprintf("A value for %v is missing in the source Terraform object Attrs", d.Path) +} + +func (d attrReadMissingDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrReadConversionFailureDiag represents diagnostic message on a failed type conversion on read +type attrReadConversionFailureDiag struct { + Path string + Type string +} + +func (d attrReadConversionFailureDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrReadConversionFailureDiag) Summary() string { + return "Error reading from Terraform object" +} + +func (d attrReadConversionFailureDiag) Detail() string { + return fmt.Sprintf("A value for %v can not be converted to %v", d.Path, d.Type) +} + +func (d attrReadConversionFailureDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteMissingDiag represents diagnostic message on an attribute missing in the target object +type attrWriteMissingDiag struct { + Path string +} + +func (d attrWriteMissingDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteMissingDiag) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteMissingDiag) Detail() string { + return fmt.Sprintf("A value for %v is missing in the source Terraform object AttrTypes", d.Path) +} + +func (d attrWriteMissingDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteConversionFailureDiag represents diagnostic message on a failed type conversion on write +type attrWriteConversionFailureDiag struct { + Path string + Type string +} + +func (d attrWriteConversionFailureDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteConversionFailureDiag) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteConversionFailureDiag) Detail() string { + return fmt.Sprintf("A value for %v can not be converted to %v", d.Path, d.Type) +} + +func (d attrWriteConversionFailureDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteGeneralError represents diagnostic message on a generic error on write +type attrWriteGeneralError struct { + Path string + Err error +} + +func (d attrWriteGeneralError) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteGeneralError) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteGeneralError) Detail() string { + return fmt.Sprintf("%s: %s", d.Path, d.Err.Error()) +} + +func (d attrWriteGeneralError) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} diff --git a/lib/services/presets.go b/lib/services/presets.go index 75e7adfe6e0c9..068bccba13e04 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -608,6 +608,7 @@ func NewPresetTerraformProviderRole() types.Role { types.KindBot, types.KindInstaller, types.KindAccessMonitoringRule, + types.KindStaticHostUser, }, Verbs: RW(), },