From 10e4ae33e67ee863425bec91a891ddf0d2991be0 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 5 Oct 2023 14:29:51 -0400 Subject: [PATCH] feat(datasource): `pinecone_collection` (#4) * feat(datasource): `pinecone_collection` * chore: text updates * chore: update learnings --- README.md | 10 +-- examples/data-source/main.tf | 18 +++++ examples/data-source/terraform.tf | 7 ++ examples/data-source/variables.tf | 8 ++ internal/data-sources/collection.go | 118 ++++++++++++++++++++++++++++ internal/provider/provider.go | 5 +- internal/resources/index.go | 14 +++- learning/log.md | 15 ++++ 8 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 examples/data-source/main.tf create mode 100644 examples/data-source/terraform.tf create mode 100644 examples/data-source/variables.tf create mode 100644 internal/data-sources/collection.go diff --git a/README.md b/README.md index 317bdd3..6fb8095 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ ```hcl terraform { - required_providers { - pinecone = { - source ="thekevinwang.com/terraform-providers/pinecone" - } - } + required_providers { + pinecone = { + source ="thekevinwang.com/terraform-providers/pinecone" + } + } } provider "pinecone" {} diff --git a/examples/data-source/main.tf b/examples/data-source/main.tf new file mode 100644 index 0000000..aa37e00 --- /dev/null +++ b/examples/data-source/main.tf @@ -0,0 +1,18 @@ +provider "pinecone" { + apikey = var.pinecone_api_key + environment = var.pinecone_environment +} + +data "pinecone_collection" "existing-collection" { + name = "testindex" +} + +resource "pinecone_index" "my-first-index" { + name = "testidx" + metric = "cosine" + pods = 1 + + source_collection = data.pinecone_collection.existing-collection.name + # index and collection dimension must match + dimension = data.pinecone_collection.existing-collection.dimension +} diff --git a/examples/data-source/terraform.tf b/examples/data-source/terraform.tf new file mode 100644 index 0000000..8e23484 --- /dev/null +++ b/examples/data-source/terraform.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + pinecone = { + source = "thekevinwang.com/terraform-providers/pinecone" + } + } +} diff --git a/examples/data-source/variables.tf b/examples/data-source/variables.tf new file mode 100644 index 0000000..35d24e3 --- /dev/null +++ b/examples/data-source/variables.tf @@ -0,0 +1,8 @@ +variable "pinecone_api_key" { + type = string + sensitive = true +} + +variable "pinecone_environment" { + type = string +} diff --git a/internal/data-sources/collection.go b/internal/data-sources/collection.go new file mode 100644 index 0000000..adecf67 --- /dev/null +++ b/internal/data-sources/collection.go @@ -0,0 +1,118 @@ +package data_sources + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + + services "github.com/thiskevinwang/terraform-provider-pinecone/internal/services" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var ( + _ datasource.DataSource = &CollectionDataSource{} +) + +func NewCollectionDataSource() datasource.DataSource { + return &CollectionDataSource{} +} + +// CollectionDataSource defines the data source implementation. +type CollectionDataSource struct { + client services.Pinecone +} + +// CollectionDataSourceModel describes the data source data model. +type CollectionDataSourceModel struct { + Name types.String `tfsdk:"name"` + Dimension types.Int64 `tfsdk:"dimension"` + Id types.String `tfsdk:"id"` +} + +func (d *CollectionDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_collection" +} + +func (d *CollectionDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: `A Pinecone collection +- See [Understanding collections](https://docs.pinecone.io/docs/collections) +- See [API Docs](https://docs.pinecone.io/reference/describe_collection) +`, + + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the collection", + Required: true, + }, + "dimension": schema.Int64Attribute{ + MarkdownDescription: "The dimension of the collection", + Required: false, + Computed: true, + }, + "id": schema.StringAttribute{ + MarkdownDescription: "Example identifier", + Computed: true, + }, + }, + } +} + +// Configure adds the provider configured client to the datasource +func (d *CollectionDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + // extract the client from the provider data + client, ok := req.ProviderData.(services.Pinecone) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected pinecone.Pinecone, got: %T", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *CollectionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data CollectionDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Generate API request body from configuration + name := data.Name.ValueString() + response, err := d.client.DescribeCollection(name) + if err != nil { + resp.Diagnostics.AddError( + "Failed to describe collection", + fmt.Sprintf("Failed to describe collection: %s", err), + ) + return + } + + // log the response + tflog.Info(ctx, "DescribeCollection OK", map[string]any{"respond": *response}) + + data.Id = types.StringValue(fmt.Sprintf("datasource-pinecone_collection-%s/%s", d.client.Environment, name)) + data.Name = types.StringValue(response.Name) + data.Dimension = types.Int64Value(response.Dimension) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index bdcf15a..77f18c6 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + datasources "github.com/thiskevinwang/terraform-provider-pinecone/internal/data-sources" resources "github.com/thiskevinwang/terraform-provider-pinecone/internal/resources" services "github.com/thiskevinwang/terraform-provider-pinecone/internal/services" ) @@ -154,7 +155,9 @@ func (p *pineconeProvider) Configure(ctx context.Context, req provider.Configure // DataSources defines the data sources implemented in the provider. func (p *pineconeProvider) DataSources(_ context.Context) []func() datasource.DataSource { - return []func() datasource.DataSource{} + return []func() datasource.DataSource{ + datasources.NewCollectionDataSource, + } } // Resources defines the resources implemented in the provider. diff --git a/internal/resources/index.go b/internal/resources/index.go index ad1e317..b2b9953 100644 --- a/internal/resources/index.go +++ b/internal/resources/index.go @@ -45,6 +45,7 @@ type indexResourceModel struct { Replicas types.Int64 `tfsdk:"replicas"` Pods types.Int64 `tfsdk:"pods"` // Shards types.Number `tfsdk:"shards"` + SourceCollection types.String `tfsdk:"source_collection"` } // Metadata returns the resource type name. @@ -90,6 +91,10 @@ func (r *indexResource) Schema(_ context.Context, _ resource.SchemaRequest, resp Computed: true, Default: int64default.StaticInt64(1), }, + "source_collection": schema.StringAttribute{ + Description: "The name of the collection to create an index from", + Optional: true, + }, }, } } @@ -130,13 +135,16 @@ func (r *indexResource) Create(ctx context.Context, req resource.CreateRequest, name := plan.Name.ValueString() dimension := plan.Dimension.ValueInt64() metric := plan.Metric.ValueString() + sourceCollection := plan.SourceCollection.ValueString() // Create new index response, err := r.client.CreateIndex(services.CreateIndexBodyParams{ - Name: name, - Dimension: dimension, - Metric: metric, + Name: name, + Dimension: dimension, + Metric: metric, + SourceCollection: sourceCollection, }) + if err != nil { resp.Diagnostics.AddError( "Failed to create index", diff --git a/learning/log.md b/learning/log.md index 994f47f..47bbc8d 100644 --- a/learning/log.md +++ b/learning/log.md @@ -255,3 +255,18 @@ Started working on tests and new-to-me golang module/import/testing isms https://github.com/hashicorp/terraform-plugin-testing/issues/185 10-05-2023 12:52pm Got a basic CREATE-DESTROY acceptance test working + +10-05-2023 12:58pm Merged: https://github.com/thiskevinwang/terraform-provider-pinecone/pull/2 + +Continue on to implement a `pinecone_collection` data-source + +10-05-2023 2:12pm Side quest fork in the road + +1. publish what I currently have to the registry +2. generate docs... for the registry + +Ask developer AI + +Login to https://registry.terraform.io/publish/provider/github/thiskevinwang + +Visit https://developer.hashicorp.com/terraform/registry/providers/publishing