From 58de81c8b5c23bcd528eac22e5374802e77fdedc Mon Sep 17 00:00:00 2001 From: Tiago Silva Date: Fri, 24 Apr 2026 15:00:14 +0100 Subject: [PATCH] sessionsearch[18]: add teleport_retrieval_model Terraform provider resource (#66059) Adds the `teleport_retrieval_model` resource and data source to the Teleport Terraform provider. RetrievalModel is a cluster-wide singleton that configures the embeddings provider used for session search, so the implementation uses the singular resource template with a fixed default name rather than the usual named-resource pattern. --- api/client/summarizer/summarizer.go | 37 + .../resources/resources.mdx | 1 + .../resources/retrieval_model.mdx | 67 ++ integrations/terraform/gen/main.go | 25 + .../protoc-gen-terraform-summarizer.yaml | 50 +- .../data_source_teleport_retrieval_model.go | 88 ++ integrations/terraform/provider/provider.go | 1 + .../resource_teleport_retrieval_model.go | 339 +++++++ .../fixtures/inference_policy_0_create.tf | 14 + .../fixtures/inference_policy_1_update.tf | 14 + .../fixtures/retrieval_model_0_create.tf | 25 + .../fixtures/retrieval_model_1_update.tf | 25 + .../testlib/inference_policy_test.go | 2 + .../terraform/testlib/retrieval_model_test.go | 146 +++ .../summarizer/v1/summarizer_terraform.go | 946 ++++++++++++++++++ lib/services/presets.go | 1 + lib/services/presets_test.go | 1 + 17 files changed, 1767 insertions(+), 15 deletions(-) create mode 100644 docs/pages/reference/infrastructure-as-code/terraform-provider/resources/retrieval_model.mdx create mode 100755 integrations/terraform/provider/data_source_teleport_retrieval_model.go create mode 100755 integrations/terraform/provider/resource_teleport_retrieval_model.go create mode 100644 integrations/terraform/testlib/fixtures/retrieval_model_0_create.tf create mode 100644 integrations/terraform/testlib/fixtures/retrieval_model_1_update.tf create mode 100644 integrations/terraform/testlib/retrieval_model_test.go diff --git a/api/client/summarizer/summarizer.go b/api/client/summarizer/summarizer.go index 25064fcdf14..35485fe6695 100644 --- a/api/client/summarizer/summarizer.go +++ b/api/client/summarizer/summarizer.go @@ -160,3 +160,40 @@ func (c *Client) DeleteInferencePolicy(ctx context.Context, name string) error { }) return trace.Wrap(err) } + +// GetRetrievalModel retrieves the existing RetrievalModel. +func (c *Client) GetRetrievalModel(ctx context.Context) (*summarizerv1.RetrievalModel, error) { + resp, err := c.grpcClient.GetRetrievalModel(ctx, &summarizerv1.GetRetrievalModelRequest{}) + if err != nil { + return nil, trace.Wrap(err) + } + return resp.Model, nil +} + +// CreateRetrievalModel creates a new RetrievalModel. +func (c *Client) CreateRetrievalModel(ctx context.Context, model *summarizerv1.RetrievalModel) (*summarizerv1.RetrievalModel, error) { + resp, err := c.grpcClient.CreateRetrievalModel(ctx, &summarizerv1.CreateRetrievalModelRequest{ + Model: model, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return resp.Model, nil +} + +// UpsertRetrievalModel creates a new RetrievalModel or updates the existing one. +func (c *Client) UpsertRetrievalModel(ctx context.Context, model *summarizerv1.RetrievalModel) (*summarizerv1.RetrievalModel, error) { + resp, err := c.grpcClient.UpsertRetrievalModel(ctx, &summarizerv1.UpsertRetrievalModelRequest{ + Model: model, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return resp.Model, nil +} + +// DeleteRetrievalModel deletes the existing RetrievalModel. +func (c *Client) DeleteRetrievalModel(ctx context.Context) error { + _, err := c.grpcClient.DeleteRetrievalModel(ctx, &summarizerv1.DeleteRetrievalModelRequest{}) + return trace.Wrap(err) +} diff --git a/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/resources.mdx b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/resources.mdx index 4f7e3e94f9b..c6d8352f87b 100644 --- a/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/resources.mdx +++ b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/resources.mdx @@ -40,6 +40,7 @@ The Teleport Terraform provider supports the following resources: - [`teleport_oidc_connector`](./oidc_connector.mdx) - [`teleport_okta_import_rule`](./okta_import_rule.mdx) - [`teleport_provision_token`](./provision_token.mdx) + - [`teleport_retrieval_model`](./retrieval_model.mdx) - [`teleport_role`](./role.mdx) - [`teleport_saml_connector`](./saml_connector.mdx) - [`teleport_saml_idp_service_provider`](./saml_idp_service_provider.mdx) diff --git a/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/retrieval_model.mdx b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/retrieval_model.mdx new file mode 100644 index 00000000000..dad02dbd323 --- /dev/null +++ b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/retrieval_model.mdx @@ -0,0 +1,67 @@ +--- +title: Reference for the teleport_retrieval_model Terraform resource +sidebar_label: retrieval_model +description: This page describes the supported values of the teleport_retrieval_model resource of the Teleport Terraform provider. +--- + +{/*Auto-generated file. Do not edit.*/} +{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} + +{/* Disable the outdated name check since resource fields occasionally need +to refer to these. */} +{/* vale 3rd-party-products.former-names = NO */} + +This page describes the supported values of the teleport_retrieval_model resource of the Teleport Terraform provider. + + + + + + +{/* schema generated by tfplugindocs */} +## Schema + +### Required + +- `spec` (Attributes) spec contains the configuration for the retrieval model, including the embeddings provider and the search inference model. In the future it can be extended with re-rankers configuration and other settings. (see [below for nested schema](#nested-schema-for-spec)) + +### Optional + +- `metadata` (Attributes) (see [below for nested schema](#nested-schema-for-metadata)) +- `sub_kind` (String) SubKind is the resource sub-kind. Should be empty. +- `version` (String) Version is the resource version. Should be set to "v1". + +### Nested Schema for `spec` + +Optional: + +- `bedrock` (Attributes) Bedrock indicates that this model uses Amazon Bedrock as the embeddings provider and specifies Bedrock-specific parameters. (see [below for nested schema](#nested-schema-for-specbedrock)) +- `inference_model_name` (String) inference_model_name is the name of the model used to convert natural language search queries into API requests and generate prose from a session summary. +- `openai` (Attributes) Openai indicates that this model uses OpenAI as the embeddings provider and specifies OpenAI-specific parameters. (see [below for nested schema](#nested-schema-for-specopenai)) + +### Nested Schema for `spec.bedrock` + +Optional: + +- `bedrock_model_id` (String) BedrockModelId specifies a model ID or an inference profile as understood by the Bedrock API. +- `integration` (String) Integration is the AWS OIDC Integration name. If unset, Teleport will use AWS credentials available on the Auth Service machine; otherwise, it will use the specified OIDC integration for assuming appropriate role. +- `region` (String) Region is the AWS region which will be used for inference. + + +### Nested Schema for `spec.openai` + +Optional: + +- `api_key_secret_ref` (String) ApiKeySecretRef is a reference to an InferenceSecret that contains the OpenAI API key. +- `base_url` (String) BaseUrl is the OpenAI API base URL. Optional, defaults to the public OpenAI API URL. May be used to point to a custom OpenAI-compatible API, such as LiteLLM. In such case, the `api_key_secret_ref` must point to a secret that contains the API key for that custom API. +- `openai_model_id` (String) OpenaiModelId specifies the model ID, as understood by the OpenAI API. + + + +### Nested Schema for `metadata` + +Optional: + +- `description` (String) description is object description. +- `expires` (String) expires is a global expiry time header can be set on any resource in the system. +- `labels` (Map of String) labels is a set of labels. diff --git a/integrations/terraform/gen/main.go b/integrations/terraform/gen/main.go index 5bb1eca5bc4..e5d2b3571a3 100644 --- a/integrations/terraform/gen/main.go +++ b/integrations/terraform/gen/main.go @@ -991,6 +991,29 @@ var ( WithoutImportState: true, } + retrievalModel = payload{ + Name: "RetrievalModel", + VarName: "retrievalModel", + TypeName: "RetrievalModel", + GetMethod: "SummarizerClient().GetRetrievalModel", + CreateMethod: "SummarizerClient().CreateRetrievalModel", + UpdateMethod: "SummarizerClient().UpsertRetrievalModel", + UpsertMethodArity: 2, + DeleteMethod: "SummarizerClient().DeleteRetrievalModel", + ID: "apitypes.MetaNameRetrievalModel", + DefaultName: "apitypes.MetaNameRetrievalModel", + Kind: "retrieval_model", + HasStaticID: false, + ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/summarizer/v1", + ProtoPackage: "summarizerv1", + SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/summarizer/v1", + SchemaPackage: "schemav1", + TerraformResourceType: "teleport_retrieval_model", + IsPlainStruct: true, + ExtraImports: []string{"apitypes \"github.com/gravitational/teleport/api/types\""}, + ForceSetKind: "apitypes.KindRetrievalModel", + } + inferencePolicy = payload{ Name: "InferencePolicy", VarName: "inferencePolicy", @@ -1190,6 +1213,8 @@ func genTFSchema() { generateDataSource(inferenceSecret, pluralDataSource) generateResource(inferencePolicy, pluralResource) generateDataSource(inferencePolicy, pluralDataSource) + generateResource(retrievalModel, singularResource) + generateDataSource(retrievalModel, singularDataSource) generateResource(scopedToken, pluralResource) generateDataSource(scopedToken, pluralDataSource) generateResource(workloadCluster, pluralResource) diff --git a/integrations/terraform/protoc-gen-terraform-summarizer.yaml b/integrations/terraform/protoc-gen-terraform-summarizer.yaml index 07fc9fbaecf..dc5a83392f9 100644 --- a/integrations/terraform/protoc-gen-terraform-summarizer.yaml +++ b/integrations/terraform/protoc-gen-terraform-summarizer.yaml @@ -9,6 +9,7 @@ types: - "InferenceModel" - "InferenceSecret" - "InferencePolicy" + - "RetrievalModel" # These import paths were not being automatically picked up by # protoc-gen-terraform without these overrides @@ -47,12 +48,24 @@ injected_fields: plan_modifiers: - "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()" + RetrievalModel: + - + 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) - "InferenceModel.metadata.id" - "InferenceSecret.metadata.id" - "InferencePolicy.metadata.id" + - "RetrievalModel.metadata.id" + # RetrievalModel is a singleton; its name is always "retrieval-model" and is set + # automatically by the provider, so it must not be exposed as a schema field. + - "RetrievalModel.metadata.name" # Temperature fields need to be excluded because of # https://discuss.hashicorp.com/t/terraform-plugin-framework-float64-type-validation-error/48645/4 @@ -60,6 +73,8 @@ exclude_fields: # later. - "InferenceModel.spec.openai.temperature" - "InferenceModel.spec.bedrock.temperature" + - "RetrievalModel.spec.openai.temperature" + - "RetrievalModel.spec.bedrock.temperature" # These fields will be marked as Computed: true computed_fields: @@ -75,23 +90,28 @@ computed_fields: - "InferencePolicy.metadata.expires" - "InferencePolicy.metadata.namespace" - "InferencePolicy.metadata.revision" + - "RetrievalModel.kind" + - "RetrievalModel.metadata.expires" + - "RetrievalModel.metadata.namespace" + - "RetrievalModel.metadata.revision" # These fields will be marked as Required: true required_fields: - - "InferenceModel.metadata" - - "InferenceModel.metadata.name" - - "InferenceModel.spec" - - "InferenceSecret.metadata" - - "InferenceSecret.metadata.name" - - "InferenceSecret.spec" - - "InferenceSecret.spec.value" - - "InferencePolicy.metadata" - - "InferencePolicy.metadata.name" - - "InferencePolicy.metadata" - - "InferencePolicy.metadata.name" - - "InferencePolicy.spec" - - "InferencePolicy.spec.kinds" - - "InferencePolicy.spec.model" + - "InferenceModel.metadata" + - "InferenceModel.metadata.name" + - "InferenceModel.spec" + - "InferenceSecret.metadata" + - "InferenceSecret.metadata.name" + - "InferenceSecret.spec" + - "InferenceSecret.spec.value" + - "InferencePolicy.metadata" + - "InferencePolicy.metadata.name" + - "InferencePolicy.metadata" + - "InferencePolicy.metadata.name" + - "InferencePolicy.spec" + - "InferencePolicy.spec.kinds" + - "InferencePolicy.spec.model" + - "RetrievalModel.spec" plan_modifiers: # Force to recreate resource if it's name changes @@ -115,8 +135,8 @@ custom_types: "InferenceModel.metadata.expires": Timestamp "InferenceSecret.metadata.expires": Timestamp "InferencePolicy.metadata.expires": Timestamp + "RetrievalModel.metadata.expires": Timestamp sensitive_fields: - "InferenceSecret.spec" - "InferenceSecret.spec.value" - \ No newline at end of file diff --git a/integrations/terraform/provider/data_source_teleport_retrieval_model.go b/integrations/terraform/provider/data_source_teleport_retrieval_model.go new file mode 100755 index 00000000000..4f6d9078c74 --- /dev/null +++ b/integrations/terraform/provider/data_source_teleport_retrieval_model.go @@ -0,0 +1,88 @@ +// 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/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/summarizer/v1" +) + +// dataSourceTeleportRetrievalModelType is the data source metadata type +type dataSourceTeleportRetrievalModelType struct{} + +// dataSourceTeleportRetrievalModel is the resource +type dataSourceTeleportRetrievalModel struct { + p Provider +} + +// GetSchema returns the data source schema +func (r dataSourceTeleportRetrievalModelType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaRetrievalModel(ctx) +} + +// NewDataSource creates the empty data source +func (r dataSourceTeleportRetrievalModelType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) { + return dataSourceTeleportRetrievalModel{ + p: *(p.(*Provider)), + }, nil +} + +// Read reads teleport RetrievalModel +func (r dataSourceTeleportRetrievalModel) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) { + retrievalModelI, err := r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + var state types.Object + resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + retrievalModel := retrievalModelI + diags := schemav1.CopyRetrievalModelToTerraform(ctx, retrievalModel, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Todo: Remove after updating terraform-plugin to >=v1.5.0. + // terraform-plugin-testing version <1.5.0 requires data resources to + // implement the 'id' attribute. + // https://developer.hashicorp.com/terraform/plugin/framework/acctests#no-id-found-in-attributes + v, ok := state.Attrs["id"] + if !ok || v.IsNull() { + id := retrievalModel.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/provider/provider.go b/integrations/terraform/provider/provider.go index cb0ecec1627..ea0a6bbb384 100644 --- a/integrations/terraform/provider/provider.go +++ b/integrations/terraform/provider/provider.go @@ -582,6 +582,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp "teleport_inference_model": resourceTeleportInferenceModelType{}, "teleport_inference_secret": resourceTeleportInferenceSecretType{}, "teleport_inference_policy": resourceTeleportInferencePolicyType{}, + "teleport_retrieval_model": resourceTeleportRetrievalModelType{}, "teleport_scoped_token": resourceTeleportScopedTokenType{}, "teleport_workload_cluster": resourceTeleportWorkloadClusterType{}, }, nil diff --git a/integrations/terraform/provider/resource_teleport_retrieval_model.go b/integrations/terraform/provider/resource_teleport_retrieval_model.go new file mode 100755 index 00000000000..0dc23e98ec2 --- /dev/null +++ b/integrations/terraform/provider/resource_teleport_retrieval_model.go @@ -0,0 +1,339 @@ +// 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" + + summarizerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/summarizer/v1" + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + "github.com/gravitational/teleport/api/utils/retryutils" + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/summarizer/v1" +) + +// resourceTeleportRetrievalModelType is the resource metadata type +type resourceTeleportRetrievalModelType struct{} + +// resourceTeleportRetrievalModel is the resource +type resourceTeleportRetrievalModel struct { + p Provider +} + +// GetSchema returns the resource schema +func (r resourceTeleportRetrievalModelType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaRetrievalModel(ctx) +} + +// NewResource creates the empty resource +func (r resourceTeleportRetrievalModelType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) { + return resourceTeleportRetrievalModel{ + p: *(p.(*Provider)), + }, nil +} + +// Create creates the RetrievalModel +func (r resourceTeleportRetrievalModel) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) { + if !r.p.IsConfigured(resp.Diagnostics) { + return + } + + var plan types.Object + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + retrievalModel := &summarizerv1.RetrievalModel{} + diags = schemav1.CopyRetrievalModelFromTerraform(ctx, plan, retrievalModel) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + retrievalModel.Kind = apitypes.KindRetrievalModel + + + if retrievalModel.GetMetadata() == nil { + retrievalModel.Metadata = &headerv1.Metadata{} + } + if retrievalModel.GetMetadata().GetName() == "" { + retrievalModel.Metadata.Name = apitypes.MetaNameRetrievalModel + } + + retrievalModelBefore, err := r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if err != nil && !trace.IsNotFound(err) { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + _, err = r.p.Client.SummarizerClient().CreateRetrievalModel(ctx, retrievalModel) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error creating RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + // Not really an inferface, just using the same name for easier templating. + var retrievalModelI *summarizerv1.RetrievalModel + + + // Try getting the resource until it exists and is different than the previous ones. + // There are two types of singleton resources: + // - the ones who can deleted and return a trace.NotFoundErr + // - the ones who cannot be deleted, only reset. In this case, the resource revision is used to know if the change got applied. + tries := 0 + retry, err := retryutils.NewRetryV2(retryutils.RetryV2Config{ + Driver: retryutils.NewExponentialDriver(r.p.RetryConfig.Base), + First: r.p.RetryConfig.Base, + Max: r.p.RetryConfig.Cap, + Jitter: retryutils.HalfJitter, + }) + if err != nil { + return + } + for { + tries = tries + 1 + retrievalModelI, err = r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if trace.IsNotFound(err) { + select { + case <-ctx.Done(): + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(ctx.Err()), "retrieval_model")) + return + case <-retry.After(): + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading RetrievalModel (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "retrieval_model") + return + } + continue + } + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + previousMetadata := retrievalModelBefore.GetMetadata() + currentMetadata := retrievalModelI.GetMetadata() + if previousMetadata.GetRevision() != currentMetadata.GetRevision() || false { + break + } + select { + case <-ctx.Done(): + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(ctx.Err()), "retrieval_model")) + return + case <-retry.After(): + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading RetrievalModel (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "retrieval_model") + return + } + } + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + retrievalModel = retrievalModelI + + + diags = schemav1.CopyRetrievalModelToTerraform(ctx, retrievalModel, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + plan.Attrs["id"] = types.String{Value: apitypes.MetaNameRetrievalModel} + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read reads teleport RetrievalModel +func (r resourceTeleportRetrievalModel) 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 + } + + retrievalModelI, err := r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if trace.IsNotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + retrievalModel := retrievalModelI + diags = schemav1.CopyRetrievalModelToTerraform(ctx, retrievalModel, &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 RetrievalModel +func (r resourceTeleportRetrievalModel) 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 + } + + retrievalModel := &summarizerv1.RetrievalModel{} + diags = schemav1.CopyRetrievalModelFromTerraform(ctx, plan, retrievalModel) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + retrievalModel.Kind = apitypes.KindRetrievalModel + if retrievalModel.GetMetadata() == nil { + retrievalModel.Metadata = &headerv1.Metadata{} + } + if retrievalModel.GetMetadata().GetName() == "" { + retrievalModel.Metadata.Name = apitypes.MetaNameRetrievalModel + } + + retrievalModelBefore, err := r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + _, err = r.p.Client.SummarizerClient().UpsertRetrievalModel(ctx, retrievalModel) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error updating RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + var retrievalModelI *summarizerv1.RetrievalModel + + tries := 0 + retry, err := retryutils.NewRetryV2(retryutils.RetryV2Config{ + Driver: retryutils.NewExponentialDriver(r.p.RetryConfig.Base), + First: r.p.RetryConfig.Base, + Max: r.p.RetryConfig.Cap, + Jitter: retryutils.HalfJitter, + }) + if err != nil { + return + } + for { + tries = tries + 1 + retrievalModelI, err = r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + if retrievalModelBefore.GetMetadata().Revision != retrievalModelI.GetMetadata().Revision || false { + break + } + select { + case <-ctx.Done(): + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(ctx.Err()), "retrieval_model")) + return + case <-retry.After(): + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading RetrievalModel (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "retrieval_model") + return + } + } + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + retrievalModel = retrievalModelI + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete deletes Teleport RetrievalModel +func (r resourceTeleportRetrievalModel) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) { + err := r.p.Client.SummarizerClient().DeleteRetrievalModel(ctx) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error deleting RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + + resp.State.RemoveResource(ctx) +} + +// ImportState imports RetrievalModel state +func (r resourceTeleportRetrievalModel) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) { + retrievalModelI, err := r.p.Client.SummarizerClient().GetRetrievalModel(ctx) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error updating RetrievalModel", trace.Wrap(err), "retrieval_model")) + return + } + retrievalModel := retrievalModelI + + var state types.Object + + diags := resp.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = schemav1.CopyRetrievalModelToTerraform(ctx, retrievalModel, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + id := retrievalModel.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/inference_policy_0_create.tf b/integrations/terraform/testlib/fixtures/inference_policy_0_create.tf index 1b819b4b923..118364fc228 100644 --- a/integrations/terraform/testlib/fixtures/inference_policy_0_create.tf +++ b/integrations/terraform/testlib/fixtures/inference_policy_0_create.tf @@ -1,3 +1,15 @@ +resource "teleport_inference_model" "prereq" { + version = "v1" + metadata = { + name = "dummy-model" + } + spec = { + openai = { + openai_model_id = "gpt-4" + } + } +} + resource "teleport_inference_policy" "test-policy" { version = "v1" metadata = { @@ -8,4 +20,6 @@ resource "teleport_inference_policy" "test-policy" { model = "dummy-model" filter = "equals(resource.metadata.labels[\"env\"], \"prod\")" } + + depends_on = [teleport_inference_model.prereq] } diff --git a/integrations/terraform/testlib/fixtures/inference_policy_1_update.tf b/integrations/terraform/testlib/fixtures/inference_policy_1_update.tf index c715f459457..222f20b22f3 100644 --- a/integrations/terraform/testlib/fixtures/inference_policy_1_update.tf +++ b/integrations/terraform/testlib/fixtures/inference_policy_1_update.tf @@ -1,3 +1,15 @@ +resource "teleport_inference_model" "prereq" { + version = "v1" + metadata = { + name = "another-dummy-model" + } + spec = { + openai = { + openai_model_id = "gpt-4" + } + } +} + resource "teleport_inference_policy" "test-policy" { version = "v1" metadata = { @@ -7,4 +19,6 @@ resource "teleport_inference_policy" "test-policy" { kinds = ["ssh", "db"] model = "another-dummy-model" } + + depends_on = [teleport_inference_model.prereq] } diff --git a/integrations/terraform/testlib/fixtures/retrieval_model_0_create.tf b/integrations/terraform/testlib/fixtures/retrieval_model_0_create.tf new file mode 100644 index 00000000000..9f6ef56bca5 --- /dev/null +++ b/integrations/terraform/testlib/fixtures/retrieval_model_0_create.tf @@ -0,0 +1,25 @@ +resource "teleport_inference_model" "prereq" { + version = "v1" + metadata = { + name = "bedrock-model" + } + spec = { + openai = { + openai_model_id = "gpt-4" + } + } +} + +resource "teleport_retrieval_model" "test" { + version = "v1" + + spec = { + bedrock = { + region = "us-west-2" + bedrock_model_id = "amazon.titan-embed-text-v2:0" + } + inference_model_name = "bedrock-model" + } + + depends_on = [teleport_inference_model.prereq] +} diff --git a/integrations/terraform/testlib/fixtures/retrieval_model_1_update.tf b/integrations/terraform/testlib/fixtures/retrieval_model_1_update.tf new file mode 100644 index 00000000000..827bc455b4d --- /dev/null +++ b/integrations/terraform/testlib/fixtures/retrieval_model_1_update.tf @@ -0,0 +1,25 @@ +resource "teleport_inference_model" "prereq" { + version = "v1" + metadata = { + name = "bedrock-model" + } + spec = { + openai = { + openai_model_id = "gpt-4" + } + } +} + +resource "teleport_retrieval_model" "test" { + version = "v1" + + spec = { + bedrock = { + region = "us-east-1" + bedrock_model_id = "amazon.titan-embed-text-v2:0" + } + inference_model_name = "bedrock-model" + } + + depends_on = [teleport_inference_model.prereq] +} diff --git a/integrations/terraform/testlib/inference_policy_test.go b/integrations/terraform/testlib/inference_policy_test.go index e51082bac3b..46e7723ea8e 100644 --- a/integrations/terraform/testlib/inference_policy_test.go +++ b/integrations/terraform/testlib/inference_policy_test.go @@ -83,6 +83,8 @@ func (s *TerraformSuiteEnterprise) TestImportInferencePolicy() { t := s.T() ctx := t.Context() + s.createInferenceModel(ctx, "some-model") + r := "teleport_inference_policy" id := "test_import" name := r + "." + id diff --git a/integrations/terraform/testlib/retrieval_model_test.go b/integrations/terraform/testlib/retrieval_model_test.go new file mode 100644 index 00000000000..8db9cce8d12 --- /dev/null +++ b/integrations/terraform/testlib/retrieval_model_test.go @@ -0,0 +1,146 @@ +// Teleport +// Copyright (C) 2026 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +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" + + summarizerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/summarizer/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/types/summarizer" +) + +func (s *TerraformSuiteEnterprise) TestRetrievalModel() { + t := s.T() + ctx := t.Context() + + checkDestroyed := func(state *terraform.State) error { + _, err := s.client.SummarizerClient().GetRetrievalModel(ctx) + if !trace.IsNotFound(err) { + return trace.Errorf("expected not found, actual: %v", err) + } + return nil + } + + name := "teleport_retrieval_model.test" + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + CheckDestroy: checkDestroyed, + IsUnitTest: true, + Steps: []resource.TestStep{ + { + Config: s.getFixture("retrieval_model_0_create.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", types.KindRetrievalModel), + resource.TestCheckResourceAttr(name, "spec.bedrock.region", "us-west-2"), + resource.TestCheckResourceAttr(name, "spec.bedrock.bedrock_model_id", "amazon.titan-embed-text-v2:0"), + resource.TestCheckResourceAttr(name, "spec.inference_model_name", "bedrock-model"), + ), + }, + { + Config: s.getFixture("retrieval_model_0_create.tf"), + PlanOnly: true, + }, + { + Config: s.getFixture("retrieval_model_1_update.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "spec.bedrock.region", "us-east-1"), + resource.TestCheckResourceAttr(name, "spec.inference_model_name", "bedrock-model"), + ), + }, + { + Config: s.getFixture("retrieval_model_1_update.tf"), + PlanOnly: true, + }, + }, + }) +} + +func (s *TerraformSuiteEnterprise) TestImportRetrievalModel() { + t := s.T() + ctx := t.Context() + + s.createInferenceModel(ctx, "bedrock-model") + + r := "teleport_retrieval_model" + id := "test_import" + name := r + "." + id + + model := summarizer.NewRetrievalModel(&summarizerv1.RetrievalModelSpec{ + EmbeddingsProvider: &summarizerv1.RetrievalModelSpec_Bedrock{ + Bedrock: &summarizerv1.BedrockProvider{ + Region: "us-west-2", + BedrockModelId: "amazon.titan-embed-text-v2:0", + }, + }, + InferenceModelName: "bedrock-model", + }) + + _, err := s.client.SummarizerClient().CreateRetrievalModel(ctx, model) + s.Require().NoError(err) + t.Cleanup(func() { + _ = s.client.SummarizerClient().DeleteRetrievalModel(context.Background()) + }) + + s.Require().Eventually(func() bool { + _, err := s.client.SummarizerClient().GetRetrievalModel(ctx) + 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 { + s.Require().Equal(types.KindRetrievalModel, state[0].Attributes["kind"]) + s.Require().Equal("us-west-2", state[0].Attributes["spec.bedrock.region"]) + s.Require().Equal("bedrock-model", state[0].Attributes["spec.inference_model_name"]) + return nil + }, + }, + }, + }) +} + +func (s *TerraformSuiteEnterprise) createInferenceModel(ctx context.Context, name string) { + s.T().Helper() + model := summarizer.NewInferenceModel(name, &summarizerv1.InferenceModelSpec{ + Provider: &summarizerv1.InferenceModelSpec_Openai{ + Openai: &summarizerv1.OpenAIProvider{ + OpenaiModelId: "gpt-4", + }, + }, + }) + _, err := s.client.SummarizerClient().UpsertInferenceModel(ctx, model) + s.Require().NoError(err) + s.T().Cleanup(func() { + // Use a fresh context: t.Context() is canceled before cleanups run. + _ = s.client.SummarizerClient().DeleteInferenceModel(context.Background(), name) + }) +} diff --git a/integrations/terraform/tfschema/summarizer/v1/summarizer_terraform.go b/integrations/terraform/tfschema/summarizer/v1/summarizer_terraform.go index b887b1aa8da..0b1c8e1f36b 100644 --- a/integrations/terraform/tfschema/summarizer/v1/summarizer_terraform.go +++ b/integrations/terraform/tfschema/summarizer/v1/summarizer_terraform.go @@ -347,6 +347,126 @@ func GenSchemaInferencePolicy(ctx context.Context) (github_com_hashicorp_terrafo }}, nil } +// GenSchemaRetrievalModel returns tfsdk.Schema definition for RetrievalModel +func GenSchemaRetrievalModel(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. Should always be set to \"retrieval_model\".", + 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, github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + Computed: true, + Description: "expires is a global expiry time header can be set on any resource in the system.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Validators: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributeValidator{github_com_gravitational_teleport_integrations_terraform_tfschema.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}, + }, + "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": { + Computed: true, + 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, + 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, + }, + }), + Description: "", + Optional: true, + }, + "spec": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "bedrock": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "bedrock_model_id": { + Description: "BedrockModelId specifies a model ID or an inference profile as understood by the Bedrock API.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "integration": { + Description: "Integration is the AWS OIDC Integration name. If unset, Teleport will use AWS credentials available on the Auth Service machine; otherwise, it will use the specified OIDC integration for assuming appropriate role.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "region": { + Description: "Region is the AWS region which will be used for inference.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Bedrock indicates that this model uses Amazon Bedrock as the embeddings provider and specifies Bedrock-specific parameters.", + Optional: true, + }, + "inference_model_name": { + Description: "inference_model_name is the name of the model used to convert natural language search queries into API requests and generate prose from a session summary.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "openai": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "api_key_secret_ref": { + Description: "ApiKeySecretRef is a reference to an InferenceSecret that contains the OpenAI API key.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "base_url": { + Description: "BaseUrl is the OpenAI API base URL. Optional, defaults to the public OpenAI API URL. May be used to point to a custom OpenAI-compatible API, such as LiteLLM. In such case, the `api_key_secret_ref` must point to a secret that contains the API key for that custom API.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "openai_model_id": { + Description: "OpenaiModelId specifies the model ID, as understood by the OpenAI API.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Openai indicates that this model uses OpenAI as the embeddings provider and specifies OpenAI-specific parameters.", + Optional: true, + }, + }), + Description: "spec contains the configuration for the retrieval model, including the embeddings provider and the search inference model. In the future it can be extended with re-rankers configuration and other settings.", + Required: true, + }, + "sub_kind": { + Description: "SubKind is the resource sub-kind. Should be empty.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "version": { + Description: "Version is the resource version. Should be set to \"v1\".", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }}, nil +} + // CopyInferenceModelFromTerraform copies contents of the source Terraform object into a target struct func CopyInferenceModelFromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.InferenceModel) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics @@ -2375,6 +2495,832 @@ func CopyInferencePolicyToTerraform(ctx context.Context, obj *github_com_gravita return diags } +// CopyRetrievalModelFromTerraform copies contents of the source Terraform object into a target struct +func CopyRetrievalModelFromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModel) 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{"RetrievalModel.kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.sub_kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.version"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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["namespace"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.metadata.namespace"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata.description"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata.labels"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.metadata.expires"}) + } + CopyFromTimestamp(diags, a, &obj.Expires) + } + { + a, ok := tf.Attrs["revision"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.metadata.revision"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.spec"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.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_summarizer_v1.RetrievalModelSpec{} + obj := obj.Spec + obj.EmbeddingsProvider = nil + { + a, ok := tf.Attrs["openai"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.openai"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.openai", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + if !v.Null && !v.Unknown { + b := &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.OpenAIProvider{} + obj.EmbeddingsProvider = &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Openai{Openai: b} + obj := b + tf := v + { + a, ok := tf.Attrs["openai_model_id"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.openai.openai_model_id"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.openai.openai_model_id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.OpenaiModelId = t + } + } + } + { + a, ok := tf.Attrs["api_key_secret_ref"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.openai.api_key_secret_ref"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.openai.api_key_secret_ref", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.ApiKeySecretRef = t + } + } + } + { + a, ok := tf.Attrs["base_url"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.openai.base_url"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.openai.base_url", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.BaseUrl = t + } + } + } + } + } + } + } + { + a, ok := tf.Attrs["bedrock"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.bedrock"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.bedrock", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + if !v.Null && !v.Unknown { + b := &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.BedrockProvider{} + obj.EmbeddingsProvider = &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Bedrock{Bedrock: b} + obj := b + tf := v + { + a, ok := tf.Attrs["region"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.bedrock.region"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.bedrock.region", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Region = t + } + } + } + { + a, ok := tf.Attrs["bedrock_model_id"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.bedrock.bedrock_model_id"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.bedrock.bedrock_model_id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.BedrockModelId = t + } + } + } + { + a, ok := tf.Attrs["integration"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.bedrock.integration"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.bedrock.integration", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Integration = t + } + } + } + } + } + } + } + { + a, ok := tf.Attrs["inference_model_name"] + if !ok { + diags.Append(attrReadMissingDiag{"RetrievalModel.spec.inference_model_name"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"RetrievalModel.spec.inference_model_name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.InferenceModelName = t + } + } + } + } + } + } + } + return diags +} + +// CopyRetrievalModelToTerraform copies contents of the source Terraform object into a target struct +func CopyRetrievalModelToTerraform(ctx context.Context, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModel, 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{"RetrievalModel.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{"RetrievalModel.kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.sub_kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.version", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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["namespace"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.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{"RetrievalModel.metadata.namespace", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.metadata.description", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata.labels"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.MapType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.metadata.labels", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.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{"RetrievalModel.metadata.revision", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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{"RetrievalModel.spec"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.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["openai"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.openai"}) + } else { + obj, ok := obj.EmbeddingsProvider.(*github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Openai) + if !ok { + obj = &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Openai{} + } + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.openai", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["openai"].(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.Openai == nil { + v.Null = true + } else { + obj := obj.Openai + tf := &v + { + t, ok := tf.AttrTypes["openai_model_id"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.openai.openai_model_id"}) + } else { + v, ok := tf.Attrs["openai_model_id"].(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{"RetrievalModel.spec.openai.openai_model_id", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.openai.openai_model_id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.OpenaiModelId) == "" + } + v.Value = string(obj.OpenaiModelId) + v.Unknown = false + tf.Attrs["openai_model_id"] = v + } + } + { + t, ok := tf.AttrTypes["api_key_secret_ref"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.openai.api_key_secret_ref"}) + } else { + v, ok := tf.Attrs["api_key_secret_ref"].(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{"RetrievalModel.spec.openai.api_key_secret_ref", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.openai.api_key_secret_ref", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.ApiKeySecretRef) == "" + } + v.Value = string(obj.ApiKeySecretRef) + v.Unknown = false + tf.Attrs["api_key_secret_ref"] = v + } + } + { + t, ok := tf.AttrTypes["base_url"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.openai.base_url"}) + } else { + v, ok := tf.Attrs["base_url"].(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{"RetrievalModel.spec.openai.base_url", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.openai.base_url", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.BaseUrl) == "" + } + v.Value = string(obj.BaseUrl) + v.Unknown = false + tf.Attrs["base_url"] = v + } + } + } + v.Unknown = false + tf.Attrs["openai"] = v + } + } + } + { + a, ok := tf.AttrTypes["bedrock"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.bedrock"}) + } else { + obj, ok := obj.EmbeddingsProvider.(*github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Bedrock) + if !ok { + obj = &github_com_gravitational_teleport_api_gen_proto_go_teleport_summarizer_v1.RetrievalModelSpec_Bedrock{} + } + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.bedrock", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["bedrock"].(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.Bedrock == nil { + v.Null = true + } else { + obj := obj.Bedrock + tf := &v + { + t, ok := tf.AttrTypes["region"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.bedrock.region"}) + } else { + v, ok := tf.Attrs["region"].(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{"RetrievalModel.spec.bedrock.region", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.bedrock.region", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Region) == "" + } + v.Value = string(obj.Region) + v.Unknown = false + tf.Attrs["region"] = v + } + } + { + t, ok := tf.AttrTypes["bedrock_model_id"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.bedrock.bedrock_model_id"}) + } else { + v, ok := tf.Attrs["bedrock_model_id"].(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{"RetrievalModel.spec.bedrock.bedrock_model_id", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.bedrock.bedrock_model_id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.BedrockModelId) == "" + } + v.Value = string(obj.BedrockModelId) + v.Unknown = false + tf.Attrs["bedrock_model_id"] = v + } + } + { + t, ok := tf.AttrTypes["integration"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.bedrock.integration"}) + } else { + v, ok := tf.Attrs["integration"].(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{"RetrievalModel.spec.bedrock.integration", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.bedrock.integration", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Integration) == "" + } + v.Value = string(obj.Integration) + v.Unknown = false + tf.Attrs["integration"] = v + } + } + } + v.Unknown = false + tf.Attrs["bedrock"] = v + } + } + } + { + t, ok := tf.AttrTypes["inference_model_name"] + if !ok { + diags.Append(attrWriteMissingDiag{"RetrievalModel.spec.inference_model_name"}) + } else { + v, ok := tf.Attrs["inference_model_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{"RetrievalModel.spec.inference_model_name", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"RetrievalModel.spec.inference_model_name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.InferenceModelName) == "" + } + v.Value = string(obj.InferenceModelName) + v.Unknown = false + tf.Attrs["inference_model_name"] = v + } + } + } + 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 diff --git a/lib/services/presets.go b/lib/services/presets.go index a798df6641f..67ab2074504 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -840,6 +840,7 @@ func NewPresetTerraformProviderRole() types.Role { types.NewRule(types.KindInferenceModel, RW()), types.NewRule(types.KindInferenceSecret, RW()), types.NewRule(types.KindInferencePolicy, RW()), + types.NewRule(types.KindRetrievalModel, RW()), types.NewRule(types.KindSAMLIdPServiceProvider, RW()), types.NewRule(types.KindScopedToken, RW()), }, diff --git a/lib/services/presets_test.go b/lib/services/presets_test.go index cb35c9e5612..2cb1df9eb45 100644 --- a/lib/services/presets_test.go +++ b/lib/services/presets_test.go @@ -776,6 +776,7 @@ func TestAddRoleDefaults(t *testing.T) { types.NewRule(types.KindInferenceModel, RW()), types.NewRule(types.KindInferenceSecret, RW()), types.NewRule(types.KindInferencePolicy, RW()), + types.NewRule(types.KindRetrievalModel, RW()), types.NewRule(types.KindScopedToken, RW()), }, },