Skip to content

Commit

Permalink
Refactor the TF Provider to use the experimental Go SDK CloudOpsAPICl…
Browse files Browse the repository at this point in the history
…ient Issue #120 (#121)

* reset my branch with main, refactored client.go to use the sdk client. refactored all other .go files to use the sdk provided protos

* change client references within resource.go files

* udpated datasources

* clean up of client.go.

* added go/sdk to the README under Requirements

* added go/sdk to the README under Requirements
  • Loading branch information
jlacefie authored Sep 24, 2024
1 parent 2c98152 commit cab53e3
Show file tree
Hide file tree
Showing 28 changed files with 250 additions and 6,454 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Interact with [Temporal Cloud](https://temporal.io/cloud) resources.

- [Terraform](https://developer.hashicorp.com/terraform/downloads) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.19
- [Temporal SDK](https://github.com/temporalio/sdk-go) >= 1.26.0

### Building

Expand Down
44 changes: 29 additions & 15 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/temporalio/terraform-provider-temporalcloud
go 1.21

require (
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/terraform-plugin-docs v0.18.0
github.com/hashicorp/terraform-plugin-framework v1.3.5
Expand All @@ -13,9 +12,9 @@ require (
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.4.0
github.com/jpillora/maplock v0.0.0-20160420012925-5c725ac6e22a
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe
google.golang.org/grpc v1.61.1
google.golang.org/protobuf v1.32.0
go.temporal.io/api v1.38.0
go.temporal.io/sdk v1.29.1
google.golang.org/grpc v1.65.0
)

require (
Expand All @@ -30,10 +29,16 @@ require (
github.com/armon/go-radix v1.0.0 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/hashicorp/cli v1.1.6 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
Expand Down Expand Up @@ -62,26 +67,35 @@ require (
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/nexus-rpc/sdk-go v0.0.10 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/yuin/goldmark v1.6.0 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zclconf/go-cty v1.14.1 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
180 changes: 145 additions & 35 deletions go.sum

Large diffs are not rendered by default.

47 changes: 0 additions & 47 deletions internal/client/apikey.go

This file was deleted.

95 changes: 19 additions & 76 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,16 @@ package client

import (
"context"
"crypto/tls"
"errors"
"fmt"
"net/url"
"strings"

"time"

grpcretry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
"github.com/hashicorp/terraform-plugin-log/tflog"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"

cloudservicev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/cloudservice/v1"
operationv1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/operation/v1"
cloudservicev1 "go.temporal.io/api/cloud/cloudservice/v1"
operationv1 "go.temporal.io/api/cloud/operation/v1"
"go.temporal.io/sdk/client"
)

const TemporalCloudAPIVersionHeader = "temporal-cloud-api-version"
Expand All @@ -48,54 +42,31 @@ var TemporalCloudAPIVersion = "2023-10-01-00"

// Client is a client for the Temporal Cloud API.
type Client struct {
cloudservicev1.CloudServiceClient
client.CloudOperationsClient
}

var (
_ cloudservicev1.CloudServiceClient = &Client{}
_ client.CloudOperationsClient = &Client{}
)

func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, opts ...grpc.DialOption) (*Client, error) {
defaultOpts := []grpc.DialOption{
grpc.WithPerRPCCredentials(NewAPIKeyRPCCredential(apiKey, allowInsecure)),
grpc.WithChainUnaryInterceptor(
grpcretry.UnaryClientInterceptor(
grpcretry.WithBackoff(
grpcretry.BackoffExponentialWithJitter(250*time.Millisecond, 0.1),
),
grpcretry.WithMax(5),
),
),
}

opts = append(defaultOpts, opts...)

return newConnection(
addrStr,
allowInsecure,
opts...,
)
}
func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string) (*Client, error) {

func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) (*Client, error) {
addr, err := url.Parse(addrStr)
if err != nil {
return nil, fmt.Errorf("unable to parse server address: %s", err)
}
defaultOpts := defaultDialOptions(addr, allowInsecure)
conn, err := grpc.Dial(
addr.String(),
append(defaultOpts, opts...)...,
)
var cClient client.CloudOperationsClient
var err error
cClient, err = client.DialCloudOperationsClient(context.Background(), client.CloudOperationsClientOptions{
Version: TemporalCloudAPIVersion,
Credentials: client.NewAPIKeyStaticCredentials(apiKey),
DisableTLS: allowInsecure,
HostPort: addrStr,
})
if err != nil {
return nil, fmt.Errorf("failed to dial `%s`: %v", addr.String(), err)
return nil, fmt.Errorf("failed to connect `%s`: %v", client.DefaultHostPort, err)
}

cloudClient := cloudservicev1.NewCloudServiceClient(conn)
return &Client{CloudServiceClient: cloudClient}, nil
return &Client{cClient}, nil
}

func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudServiceClient, op *operationv1.AsyncOperation) error {
func AwaitAsyncOperation(ctx context.Context, client client.CloudOperationsClient, op *operationv1.AsyncOperation) error {
if op == nil {
return fmt.Errorf("failed to await response: nil operation")
}
Expand All @@ -106,7 +77,7 @@ func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudService
for {
select {
case <-ticker.C:
status, err := client.GetAsyncOperation(ctx, &cloudservicev1.GetAsyncOperationRequest{
status, err := client.CloudService().GetAsyncOperation(ctx, &cloudservicev1.GetAsyncOperationRequest{
AsyncOperationId: op.Id,
})
if err != nil {
Expand Down Expand Up @@ -145,31 +116,3 @@ func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudService
}
}
}

func defaultDialOptions(addr *url.URL, allowInsecure bool) []grpc.DialOption {
var opts []grpc.DialOption

transport := credentials.NewTLS(&tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: addr.Hostname(),
})
if allowInsecure {
transport = insecure.NewCredentials()
}

opts = append(opts, grpc.WithTransportCredentials(transport))
opts = append(opts, grpc.WithUnaryInterceptor(setAPIVersionInterceptor))
return opts
}

func setAPIVersionInterceptor(
ctx context.Context,
method string,
req, reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
ctx = metadata.AppendToOutgoingContext(ctx, TemporalCloudAPIVersionHeader, strings.TrimSpace(TemporalCloudAPIVersion))
return invoker(ctx, method, req, reply, cc, opts...)
}
27 changes: 14 additions & 13 deletions internal/provider/namespace_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ import (

"github.com/temporalio/terraform-provider-temporalcloud/internal/client"
internaltypes "github.com/temporalio/terraform-provider-temporalcloud/internal/types"
cloudservicev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/cloudservice/v1"
namespacev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/namespace/v1"
cloudservicev1 "go.temporal.io/api/cloud/cloudservice/v1"
namespacev1 "go.temporal.io/api/cloud/namespace/v1"
)

const (
Expand All @@ -53,7 +53,8 @@ const (

type (
namespaceResource struct {
client cloudservicev1.CloudServiceClient
// client cloudservicev1.CloudServiceClient
client *client.Client
}

namespaceResourceModel struct {
Expand Down Expand Up @@ -121,11 +122,11 @@ func (r *namespaceResource) Configure(_ context.Context, req resource.ConfigureR
return
}

client, ok := req.ProviderData.(cloudservicev1.CloudServiceClient)
client, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected cloudservicev1.CloudServiceClient, got: %T. Please report this issue to the provider developers.", req.ProviderData),
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
Expand Down Expand Up @@ -277,7 +278,7 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque
return
}
}
svcResp, err := r.client.CreateNamespace(ctx, &cloudservicev1.CreateNamespaceRequest{
svcResp, err := r.client.CloudService().CreateNamespace(ctx, &cloudservicev1.CreateNamespaceRequest{
Spec: &namespacev1.NamespaceSpec{
Name: plan.Name.ValueString(),
Regions: regions,
Expand All @@ -299,7 +300,7 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque
return
}

ns, err := r.client.GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
ns, err := r.client.CloudService().GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
Namespace: svcResp.Namespace,
})
if err != nil {
Expand All @@ -319,7 +320,7 @@ func (r *namespaceResource) Read(ctx context.Context, req resource.ReadRequest,
return
}

model, err := r.client.GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
model, err := r.client.CloudService().GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
Namespace: state.ID.ValueString(),
})
if err != nil {
Expand Down Expand Up @@ -348,7 +349,7 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque
return
}

currentNs, err := r.client.GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
currentNs, err := r.client.CloudService().GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
Namespace: plan.ID.ValueString(),
})
if err != nil {
Expand All @@ -359,7 +360,7 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque
if resp.Diagnostics.HasError() {
return
}
svcResp, err := r.client.UpdateNamespace(ctx, &cloudservicev1.UpdateNamespaceRequest{
svcResp, err := r.client.CloudService().UpdateNamespace(ctx, &cloudservicev1.UpdateNamespaceRequest{
Namespace: plan.ID.ValueString(),
Spec: &namespacev1.NamespaceSpec{
Name: plan.Name.ValueString(),
Expand All @@ -384,7 +385,7 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque
return
}

ns, err := r.client.GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
ns, err := r.client.CloudService().GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
Namespace: plan.ID.ValueString(),
})
if err != nil {
Expand All @@ -410,7 +411,7 @@ func (r *namespaceResource) Delete(ctx context.Context, req resource.DeleteReque
return
}

currentNs, err := r.client.GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
currentNs, err := r.client.CloudService().GetNamespace(ctx, &cloudservicev1.GetNamespaceRequest{
Namespace: state.ID.ValueString(),
})
if err != nil {
Expand All @@ -419,7 +420,7 @@ func (r *namespaceResource) Delete(ctx context.Context, req resource.DeleteReque
}
ctx, cancel := context.WithTimeout(ctx, deleteTimeout)
defer cancel()
svcResp, err := r.client.DeleteNamespace(ctx, &cloudservicev1.DeleteNamespaceRequest{
svcResp, err := r.client.CloudService().DeleteNamespace(ctx, &cloudservicev1.DeleteNamespaceRequest{
Namespace: state.ID.ValueString(),
ResourceVersion: currentNs.GetNamespace().GetResourceVersion(),
})
Expand Down
Loading

0 comments on commit cab53e3

Please sign in to comment.