Skip to content

Commit

Permalink
Merge pull request #58 from amibaid/search_attribute_resource
Browse files Browse the repository at this point in the history
Search attribute resource
  • Loading branch information
ganievs authored Jul 24, 2024
2 parents 6d27847 + f6a6374 commit 67f9c46
Show file tree
Hide file tree
Showing 10 changed files with 745 additions and 0 deletions.
41 changes: 41 additions & 0 deletions docs/data-sources/search_attribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "temporal_search_attribute Data Source - terraform-provider-temporal"
subcategory: ""
description: |-
Temporal Search Attribute data source
---

# temporal_search_attribute (Data Source)

Temporal Search Attribute data source

## Example Usage

```terraform
# Get data of the example search attribute, with or without explicitly providing a namespace
data "temporal_search_attribute" "example_search_attribute" {
name = "example"
namespace = "default"
}
data "temporal_search_attribute" "example_search_attribute_no_namespace" {
name = "example"
# 'default' namespace will be used here
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) Search Attribute Name

### Optional

- `namespace` (String) Namespace with which the Search Attribute is associated. If this is not provided, 'default' will be used

### Read-Only

- `type` (String) Search Attribute Indexed Value Type, which defines the type of data stored in the attribute
53 changes: 53 additions & 0 deletions docs/resources/search_attribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "temporal_search_attribute Resource - terraform-provider-temporal"
subcategory: ""
description: |-
Temporal Search Attribute resource
---

# temporal_search_attribute (Resource)

Temporal Search Attribute resource

## Example Usage

```terraform
# Manage an example search attribute, with or without explicitly providing a namespace
resource "temporal_search_attribute" "example_search_attribute" {
name = "example"
type = "Bool"
namespace = "default"
}
resource "temporal_search_attribute" "example_search_attribute_no_namespace" {
name = "example"
type = "Bool"
# 'default' namespace will be used here
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) Search Attribute Name
- `type` (String) Search Attribute Indexed Value Type, which defines the type of data stored in the attribute

### Optional

- `namespace` (String) Namespace with which the Search Attribute is associated

## Import

Import is supported using the following syntax:

```shell
# A search attribute can be imported by specifying 'namespace:search_attibute_name'
terraform import temporal_search_attribute.example_search_attribute default:example


# A search attribute can also be imported by specifying just 'search_attibute_name' ('default' namespace will be used)
terraform import temporal_search_attribute.example_search_attribute example
```
10 changes: 10 additions & 0 deletions examples/data-sources/temporal_search_attribute/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Get data of the example search attribute, with or without explicitly providing a namespace
data "temporal_search_attribute" "example_search_attribute" {
name = "example"
namespace = "default"
}

data "temporal_search_attribute" "example_search_attribute_no_namespace" {
name = "example"
# 'default' namespace will be used here
}
6 changes: 6 additions & 0 deletions examples/resources/temporal_search_attribute/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# A search attribute can be imported by specifying 'namespace:search_attibute_name'
terraform import temporal_search_attribute.example_search_attribute default:example


# A search attribute can also be imported by specifying just 'search_attibute_name' ('default' namespace will be used)
terraform import temporal_search_attribute.example_search_attribute example
12 changes: 12 additions & 0 deletions examples/resources/temporal_search_attribute/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Manage an example search attribute, with or without explicitly providing a namespace
resource "temporal_search_attribute" "example_search_attribute" {
name = "example"
type = "Bool"
namespace = "default"
}

resource "temporal_search_attribute" "example_search_attribute_no_namespace" {
name = "example"
type = "Bool"
# 'default' namespace will be used here
}
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,15 @@ func (p *TemporalProvider) Configure(ctx context.Context, req provider.Configure
func (p *TemporalProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewNamespaceResource,
NewSearchAttributeResource,
}
}

// DataSources returns a list of data source types managed by this provider.
func (p *TemporalProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewNamespaceDataSource,
NewSearchAttributeDataSource,
}
}

Expand Down
153 changes: 153 additions & 0 deletions internal/provider/search_attribute_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package provider

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"go.temporal.io/api/enums/v1"
"go.temporal.io/api/operatorservice/v1"
"google.golang.org/grpc"
)

// Ensures that SearchAttributeDataSource fully satisfies the datasource.DataSource and
// datasource.DataSourceWithConfigure interfaces.
var (
_ datasource.DataSource = &SearchAttributeDataSource{}
_ datasource.DataSourceWithConfigure = &SearchAttributeDataSource{}
)

// NewSearchAttributeDataSource returns a new instance of the SearchAttributeDataSource.
func NewSearchAttributeDataSource() datasource.DataSource {
return &SearchAttributeDataSource{}
}

// SearchAttributeDataSource implements the Terraform data source interface for Temporal SearchAttributes.
type SearchAttributeDataSource struct {
client operatorservice.OperatorServiceClient
}

// SearchAttributeDataSourceModel defines the structure for the data source's configuration and read data.
type SearchAttributeDataSourceModel struct {
Name types.String `tfsdk:"name"`
Type types.String `tfsdk:"type"`
Namespace types.String `tfsdk:"namespace"`
}

// Metadata sets the metadata for the Temporal SearchAttribute data source, specifically the type name.
func (d *SearchAttributeDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_search_attribute"
}

// Schema defines the schema for the Temporal SearchAttribute data source.
func (d *SearchAttributeDataSource) 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: "Temporal Search Attribute data source",

Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Search Attribute Name",
Required: true,
},
"type": schema.StringAttribute{
MarkdownDescription: "Search Attribute Indexed Value Type, which defines the type of data stored in the attribute",
Computed: true,
},
"namespace": schema.StringAttribute{
MarkdownDescription: "Namespace with which the Search Attribute is associated. If this is not provided, 'default' will be used",
Optional: true,
},
},
}
}

// Configure sets up the SearchAttribute data source configuration.
func (d *SearchAttributeDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
tflog.Info(ctx, "Configuring Temporal SearchAttribute DataSource")

// Prevent panic if the provider has not been configured yet.
if req.ProviderData == nil {
return
}

connection, ok := req.ProviderData.(grpc.ClientConnInterface)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected grpc.ClientConnInterface, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

client := operatorservice.NewOperatorServiceClient(connection)
d.client = client

tflog.Info(ctx, "Configured Temporal Search Attribute client", map[string]any{"success": true})
}

// Read fetches data from a Temporal SearchAttribute and sets it in the Terraform state.
func (d *SearchAttributeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
tflog.Info(ctx, "Reading Temporal Search Attribute")

var name string
var namespace types.String

// Get the 'name' and 'namespace' attributes from the configuration
diags := req.Config.GetAttribute(ctx, path.Root("name"), &name)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

diags = req.Config.GetAttribute(ctx, path.Root("namespace"), &namespace)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// If the user has not provided a namespace for the data source, use 'default'
if namespace.IsNull() {
namespace = types.StringValue("default")
}

request := &operatorservice.ListSearchAttributesRequest{
Namespace: namespace.ValueString(),
}

// Calling API for existing attribute details
searchAttributes, err := d.client.ListSearchAttributes(ctx, request)
if err != nil {
resp.Diagnostics.AddError("API Client Error", fmt.Sprintf("Unable to read SearchAttribute: %s", err))
return
}

var attributeType enums.IndexedValueType
var found bool
if attributeType, found = searchAttributes.GetCustomAttributes()[name]; !found {
if attributeType, found = searchAttributes.GetSystemAttributes()[name]; !found {
resp.Diagnostics.AddError("Not Found", fmt.Sprintf("SearchAttribute '%s' not found in namespace '%s'", name, namespace))
return
}
}

// Prepare the data to be set in the Terraform state
data := &SearchAttributeDataSourceModel{
Name: types.StringValue(name),
Type: types.StringValue(attributeType.String()),
Namespace: namespace,
}

// Save the fetched data into Terraform state
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

tflog.Info(ctx, "SearchAttribute data source read successfully", map[string]any{"name": name, "type": attributeType.String(), "namespace": namespace})
}
46 changes: 46 additions & 0 deletions internal/provider/search_attribute_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package provider_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func TestAccSearchAttributeDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,

Steps: []resource.TestStep{
// Test reading from the server and setting data source attributes

// Test reading data source without explicitly proving namespace, should use 'default'
{
Config: providerConfig + `
data "temporal_search_attribute" "example" {
name = "RunId"
}`,

Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "name", "RunId"),
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "type", "Keyword"), // Verify that the type was read correctly from the server
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "namespace", "default"),
),
},

// Test reading with provided namespace
{
Config: providerConfig + `
data "temporal_search_attribute" "example" {
name = "HistoryLength"
namespace = "default"
}`,

Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "name", "HistoryLength"),
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "type", "Int"), // Verify that the type was read correctly from the server
resource.TestCheckResourceAttr("data.temporal_search_attribute.example", "namespace", "default"),
),
},
},
})
}
Loading

0 comments on commit 67f9c46

Please sign in to comment.