From a93a39dc52e8d5533299b1695f70c5ebc3dc9cce Mon Sep 17 00:00:00 2001 From: Kshitij Wadhwa Date: Fri, 27 Sep 2024 14:29:41 -0700 Subject: [PATCH 1/5] set apikey auth for namespaces --- docs/index.md | 1 + docs/resources/namespace.md | 3 +- internal/client/client.go | 5 +- internal/provider/namespace_resource.go | 101 +++++++++++----- internal/provider/namespace_resource_test.go | 121 ++++++++++++++++++- internal/provider/namespaces_datasource.go | 2 + internal/provider/provider.go | 27 ++++- internal/provider/user_resource_test.go | 2 +- 8 files changed, 220 insertions(+), 42 deletions(-) diff --git a/docs/index.md b/docs/index.md index 7da75dc..0792c31 100644 --- a/docs/index.md +++ b/docs/index.md @@ -59,4 +59,5 @@ provider "temporalcloud" { - `allow_insecure` (Boolean) If set to True, it allows for an insecure connection to the Temporal Cloud API. This should never be set to 'true' in production and defaults to false. - `api_key` (String, Sensitive) The API key for Temporal Cloud. See [this documentation](https://docs.temporal.io/cloud/api-keys) for information on how to obtain an API key. +- `client_version` (String) The version of the Temporal Cloud API client to use. Defaults to `2023-10-01-00`. To create namespaces with API key authentication enabled, use `2024-05-13-00`. - `endpoint` (String) The endpoint for the Temporal Cloud API. Defaults to `saas-api.tmprl.cloud:443`. diff --git a/docs/resources/namespace.md b/docs/resources/namespace.md index ab09a53..c10fc71 100644 --- a/docs/resources/namespace.md +++ b/docs/resources/namespace.md @@ -108,13 +108,14 @@ resource "temporalcloud_namespace" "terraform2" { ### Required -- `accepted_client_ca` (String) The Base64-encoded CA cert in PEM format that clients use when authenticating with Temporal Cloud. - `name` (String) The name of the namespace. - `regions` (List of String) The list of regions that this namespace is available in. If more than one region is specified, this namespace is a "Multi-region Namespace", which is currently unsupported by the Terraform provider. - `retention_days` (Number) The number of days to retain workflow history. Any changes to the retention period will be applied to all new running workflows. ### Optional +- `accepted_client_ca` (String) The Base64-encoded CA cert in PEM format that clients use when authenticating with Temporal Cloud. +- `api_key_auth` (Boolean) If true, Temporal Cloud will use API key authentication for this namespace. If false, mutual TLS (mTLS) authentication will be used. - `certificate_filters` (Attributes List) A list of filters to apply to client certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from client certificates whose distinguished name properties match at least one of the filters. (see [below for nested schema](#nestedatt--certificate_filters)) - `codec_server` (Attributes) A codec server is used by the Temporal Cloud UI to decode payloads for all users interacting with this namespace, even if the workflow history itself is encrypted. (see [below for nested schema](#nestedatt--codec_server)) - `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) diff --git a/internal/client/client.go b/internal/client/client.go index e79cca7..bc49def 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -36,7 +36,6 @@ import ( "go.temporal.io/sdk/client" ) -const TemporalCloudAPIVersionHeader = "temporal-cloud-api-version" var TemporalCloudAPIVersion = "2024-05-13-00" @@ -49,12 +48,12 @@ var ( _ client.CloudOperationsClient = &Client{} ) -func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string) (*Client, error) { +func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, clientVersion string) (*Client, error) { var cClient client.CloudOperationsClient var err error cClient, err = client.DialCloudOperationsClient(context.Background(), client.CloudOperationsClientOptions{ - Version: TemporalCloudAPIVersion, + Version: clientVersion, Credentials: client.NewAPIKeyStaticCredentials(apiKey), DisableTLS: allowInsecure, HostPort: addrStr, diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index e68a16b..b659bd5 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -64,6 +64,7 @@ type ( AcceptedClientCA internaltypes.EncodedCAValue `tfsdk:"accepted_client_ca"` RetentionDays types.Int64 `tfsdk:"retention_days"` CertificateFilters types.List `tfsdk:"certificate_filters"` + ApiKeyAuth types.Bool `tfsdk:"api_key_auth"` CodecServer types.Object `tfsdk:"codec_server"` Endpoints types.Object `tfsdk:"endpoints"` @@ -170,7 +171,7 @@ func (r *namespaceResource) Schema(ctx context.Context, _ resource.SchemaRequest "accepted_client_ca": schema.StringAttribute{ CustomType: internaltypes.EncodedCAType{}, Description: "The Base64-encoded CA cert in PEM format that clients use when authenticating with Temporal Cloud.", - Required: true, + Optional: true, }, "retention_days": schema.Int64Attribute{ Description: "The number of days to retain workflow history. Any changes to the retention period will be applied to all new running workflows.", @@ -200,6 +201,10 @@ func (r *namespaceResource) Schema(ctx context.Context, _ resource.SchemaRequest }, }, }, + "api_key_auth": schema.BoolAttribute{ + Description: "If true, Temporal Cloud will use API key authentication for this namespace. If false, mutual TLS (mTLS) authentication will be used.", + Optional: true, + }, "codec_server": schema.SingleNestedAttribute{ Description: "A codec server is used by the Temporal Cloud UI to decode payloads for all users interacting with this namespace, even if the workflow history itself is encrypted.", Attributes: map[string]schema.Attribute{ @@ -278,21 +283,40 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque return } } - mtls := &namespacev1.MtlsAuthSpec{} - if plan.AcceptedClientCA.ValueString() != "" { - mtls.Enabled = true - mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() - mtls.CertificateFilters = certFilters + + var spec = &namespacev1.NamespaceSpec{ + Name: plan.Name.ValueString(), + Regions: regions, + RetentionDays: int32(plan.RetentionDays.ValueInt64()), + CodecServer: codecServer, } + + if plan.ApiKeyAuth.ValueBool() { + spec.ApiKeyAuth = &namespacev1.ApiKeyAuthSpec{Enabled: true} + } else { + if plan.AcceptedClientCA.IsNull() { + resp.Diagnostics.AddError("accepted_client_ca is required when API key authentication is disabled", "") + return + } + var mtlAuth *namespacev1.MtlsAuthSpec + mtlAuth = &namespacev1.MtlsAuthSpec{ + AcceptedClientCa: plan.AcceptedClientCA.ValueString(), + CertificateFilters: certFilters, + } + mtls := &namespacev1.MtlsAuthSpec{} + if plan.AcceptedClientCA.ValueString() != "" { + mtls.Enabled = true + mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() + mtls.CertificateFilters = certFilters + } + + spec.MtlsAuth = mtlAuth + } + svcResp, err := r.client.CloudService().CreateNamespace(ctx, &cloudservicev1.CreateNamespaceRequest{ - Spec: &namespacev1.NamespaceSpec{ - Name: plan.Name.ValueString(), - Regions: regions, - RetentionDays: int32(plan.RetentionDays.ValueInt64()), - MtlsAuth: mtls, - CodecServer: codecServer, - }, + Spec: spec, }) + if err != nil { resp.Diagnostics.AddError("Failed to create namespace", err.Error()) return @@ -363,22 +387,35 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque if resp.Diagnostics.HasError() { return } - mtls := &namespacev1.MtlsAuthSpec{} - if plan.AcceptedClientCA.ValueString() != "" { - mtls.Enabled = true - mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() - mtls.CertificateFilters = certFilters + + var spec = &namespacev1.NamespaceSpec{ + Name: plan.Name.ValueString(), + Regions: regions, + RetentionDays: int32(plan.RetentionDays.ValueInt64()), + CodecServer: codecServer, + CustomSearchAttributes: currentNs.GetNamespace().GetSpec().GetCustomSearchAttributes(), + } + + if plan.ApiKeyAuth.ValueBool() { + spec.ApiKeyAuth = &namespacev1.ApiKeyAuthSpec{Enabled: true} + } else { + if plan.AcceptedClientCA.IsNull() { + resp.Diagnostics.AddError("accepted_client_ca is required when API key authentication is disabled", "") + return + } + mtls := &namespacev1.MtlsAuthSpec{} + if plan.AcceptedClientCA.ValueString() != "" { + mtls.Enabled = true + mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() + mtls.CertificateFilters = certFilters + } + + spec.MtlsAuth = mtlAuth } + svcResp, err := r.client.CloudService().UpdateNamespace(ctx, &cloudservicev1.UpdateNamespaceRequest{ - Namespace: plan.ID.ValueString(), - Spec: &namespacev1.NamespaceSpec{ - Name: plan.Name.ValueString(), - Regions: regions, - RetentionDays: int32(plan.RetentionDays.ValueInt64()), - MtlsAuth: mtls, - CodecServer: codecServer, - CustomSearchAttributes: currentNs.GetNamespace().GetSpec().GetCustomSearchAttributes(), - }, + Namespace: plan.ID.ValueString(), + Spec: spec, ResourceVersion: currentNs.GetNamespace().GetResourceVersion(), }) if err != nil { @@ -495,6 +532,14 @@ func updateModelFromSpec(ctx context.Context, diags diag.Diagnostics, state *nam certificateFilter = filters } + if ns.GetSpec().GetMtlsAuth().GetAcceptedClientCa() != "" { + state.AcceptedClientCA = internaltypes.EncodedCA(ns.GetSpec().GetMtlsAuth().GetAcceptedClientCa()) + } + + if ns.GetSpec().GetApiKeyAuth() != nil { + state.ApiKeyAuth = types.BoolValue(ns.GetSpec().GetApiKeyAuth().GetEnabled()) + } + var codecServerState basetypes.ObjectValue // The API always returns a non-empty CodecServerSpec, even if it wasn't specified on object creation. We explicitly // map an endpoint whose value is the empty string to `null`, since an empty endpoint implies that the codec server @@ -527,7 +572,7 @@ func updateModelFromSpec(ctx context.Context, diags diag.Diagnostics, state *nam state.Endpoints = endpointsState state.Regions = planRegions state.CertificateFilters = certificateFilter - state.AcceptedClientCA = internaltypes.EncodedCA(ns.GetSpec().GetMtlsAuth().GetAcceptedClientCa()) + state.RetentionDays = types.Int64Value(int64(ns.GetSpec().GetRetentionDays())) } diff --git a/internal/provider/namespace_resource_test.go b/internal/provider/namespace_resource_test.go index d8a1475..a4d3681 100644 --- a/internal/provider/namespace_resource_test.go +++ b/internal/provider/namespace_resource_test.go @@ -67,6 +67,39 @@ PEM } +func TestAccBasicNamespaceWithApiKeyAuth(t *testing.T) { + name := fmt.Sprintf("%s-%s", "tf-basic-namespace", randomString()) + config := func(name string, retention int) string { + return fmt.Sprintf(` +provider "temporalcloud" { + client_version = "2024-05-13-00" +} + +resource "temporalcloud_namespace" "terraform" { + name = "%s" + regions = ["aws-us-east-1"] + api_key_auth = true + retention_days = %d +}`, name, retention) + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + // New namespace with retention of 7 + Config: config(name, 7), + }, + { + Config: config(name, 14), + }, + // Delete testing automatically occurs in TestCase + }, + }) + +} + func TestAccBasicNamespaceWithCertFilters(t *testing.T) { name := fmt.Sprintf("%s-%s", "tf-cert-filters", randomString()) config := func(name string, retention int) string { @@ -134,18 +167,27 @@ func TestAccNamespaceWithCodecServer(t *testing.T) { Name string RetentionDays int CodecServer *codecServer + ApiKeyAuth bool } ) name := fmt.Sprintf("%s-%s", "tf-codec-server", randomString()) tmpl := template.Must(template.New("config").Parse(` provider "temporalcloud" { - + {{ if .ApiKeyAuth }} + client_version = "2024-05-13-00" + {{ end }} } resource "temporalcloud_namespace" "test" { - name = "{{ .Name }}" + name = "{{ .Name }}-{{ .ApiKeyAuth }}" regions = ["aws-us-east-1"] + + {{ if .ApiKeyAuth }} + api_key_auth = true + {{ end }} + + {{ if not .ApiKeyAuth }} accepted_client_ca = base64encode(< Date: Tue, 1 Oct 2024 11:38:33 -0700 Subject: [PATCH 2/5] comments --- internal/provider/namespace_resource.go | 4 ++-- internal/provider/namespaces_datasource.go | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index b659bd5..7f2b8c4 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -295,7 +295,7 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque spec.ApiKeyAuth = &namespacev1.ApiKeyAuthSpec{Enabled: true} } else { if plan.AcceptedClientCA.IsNull() { - resp.Diagnostics.AddError("accepted_client_ca is required when API key authentication is disabled", "") + resp.Diagnostics.AddError("Namespace not configured with authentication. accepted_client_ca is required when API key authentication is not enabled (api_key_auth is not set to true).", "") return } var mtlAuth *namespacev1.MtlsAuthSpec @@ -400,7 +400,7 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque spec.ApiKeyAuth = &namespacev1.ApiKeyAuthSpec{Enabled: true} } else { if plan.AcceptedClientCA.IsNull() { - resp.Diagnostics.AddError("accepted_client_ca is required when API key authentication is disabled", "") + resp.Diagnostics.AddError("Namespace not configured with authentication. accepted_client_ca is required when API key authentication is not enabled (api_key_auth is not set to true).", "") return } mtls := &namespacev1.MtlsAuthSpec{} diff --git a/internal/provider/namespaces_datasource.go b/internal/provider/namespaces_datasource.go index 18de58d..a537901 100644 --- a/internal/provider/namespaces_datasource.go +++ b/internal/provider/namespaces_datasource.go @@ -181,6 +181,10 @@ func (d *namespacesDataSource) Schema(_ context.Context, _ datasource.SchemaRequ }, }, }, + "api_key_auth": schema.BoolAttribute{ + Description: "If true, Temporal Cloud will use API key authentication for this namespace. If false, mutual TLS (mTLS) authentication will be used.", + Optional: true, + }, "codec_server": schema.SingleNestedAttribute{ Optional: true, Computed: true, @@ -304,10 +308,14 @@ func (d *namespacesDataSource) Read(ctx context.Context, req datasource.ReadRequ State: types.StringValue(ns.State), ActiveRegion: types.StringValue(ns.ActiveRegion), AcceptedClientCA: types.StringValue(ns.GetSpec().GetMtlsAuth().GetAcceptedClientCa()), - ApiKeyAuth: types.BoolValue(ns.GetSpec().GetApiKeyAuth().GetEnabled()), RetentionDays: types.Int64Value(int64(ns.GetSpec().GetRetentionDays())), CreatedTime: types.StringValue(ns.GetCreatedTime().AsTime().Format(time.RFC3339)), } + + if ns.GetSpec().GetApiKeyAuth().GetEnabled() { + namespaceModel.ApiKeyAuth = types.BoolValue(true) + } + if ns.GetLastModifiedTime().String() != "" { namespaceModel.LastModifiedTime = types.StringValue(ns.GetLastModifiedTime().AsTime().Format(time.RFC3339)) } else { From 251d1843b16b1db1231a69f7bd5ef1605f95c00b Mon Sep 17 00:00:00 2001 From: Kshitij Wadhwa Date: Tue, 1 Oct 2024 11:41:13 -0700 Subject: [PATCH 3/5] docs --- docs/data-sources/namespaces.md | 1 + docs/resources/namespace.md | 8 ++++++++ examples/resources/temporalcloud_namespace/resource.tf | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/docs/data-sources/namespaces.md b/docs/data-sources/namespaces.md index f887afa..09656c2 100644 --- a/docs/data-sources/namespaces.md +++ b/docs/data-sources/namespaces.md @@ -45,6 +45,7 @@ output "namespaces" { Optional: +- `api_key_auth` (Boolean) If true, Temporal Cloud will use API key authentication for this namespace. If false, mutual TLS (mTLS) authentication will be used. - `certificate_filters` (Attributes List) A list of filters to apply to client certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from client certificates whose distinguished name properties match at least one of the filters. (see [below for nested schema](#nestedatt--namespaces--certificate_filters)) - `codec_server` (Attributes) A codec server is used by the Temporal Cloud UI to decode payloads for all users interacting with this namespace, even if the workflow history itself is encrypted. (see [below for nested schema](#nestedatt--namespaces--codec_server)) - `custom_search_attributes` (Map of String) The custom search attributes to use for the namespace. diff --git a/docs/resources/namespace.md b/docs/resources/namespace.md index c10fc71..26de13f 100644 --- a/docs/resources/namespace.md +++ b/docs/resources/namespace.md @@ -101,6 +101,14 @@ resource "temporalcloud_namespace" "terraform2" { accepted_client_ca = base64encode(tls_self_signed_cert.ca.cert_pem) retention_days = 14 } + +// example namespace that uses API Key for authentication +resource "temporalcloud_namespace" "terraform3" { + name = "terraform3" + regions = ["aws-us-east-1"] + api_key_auth = true + retention_days = 14 +} ``` diff --git a/examples/resources/temporalcloud_namespace/resource.tf b/examples/resources/temporalcloud_namespace/resource.tf index 002c8ed..a6fdee3 100644 --- a/examples/resources/temporalcloud_namespace/resource.tf +++ b/examples/resources/temporalcloud_namespace/resource.tf @@ -85,4 +85,12 @@ resource "temporalcloud_namespace" "terraform2" { regions = ["aws-us-east-1"] accepted_client_ca = base64encode(tls_self_signed_cert.ca.cert_pem) retention_days = 14 +} + +// example namespace that uses API Key for authentication +resource "temporalcloud_namespace" "terraform3" { + name = "terraform3" + regions = ["aws-us-east-1"] + api_key_auth = true + retention_days = 14 } \ No newline at end of file From a40d8aeb984fad690f67563c0c07a231789351ab Mon Sep 17 00:00:00 2001 From: Kshitij Wadhwa Date: Wed, 2 Oct 2024 12:52:17 -0700 Subject: [PATCH 4/5] remove client_version --- docs/index.md | 1 - internal/client/client.go | 6 +++-- internal/provider/namespace_resource_test.go | 25 +++++++------------- internal/provider/provider.go | 23 +----------------- internal/provider/user_resource_test.go | 2 +- 5 files changed, 14 insertions(+), 43 deletions(-) diff --git a/docs/index.md b/docs/index.md index 0792c31..7da75dc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -59,5 +59,4 @@ provider "temporalcloud" { - `allow_insecure` (Boolean) If set to True, it allows for an insecure connection to the Temporal Cloud API. This should never be set to 'true' in production and defaults to false. - `api_key` (String, Sensitive) The API key for Temporal Cloud. See [this documentation](https://docs.temporal.io/cloud/api-keys) for information on how to obtain an API key. -- `client_version` (String) The version of the Temporal Cloud API client to use. Defaults to `2023-10-01-00`. To create namespaces with API key authentication enabled, use `2024-05-13-00`. - `endpoint` (String) The endpoint for the Temporal Cloud API. Defaults to `saas-api.tmprl.cloud:443`. diff --git a/internal/client/client.go b/internal/client/client.go index bc49def..6a4037c 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -48,12 +48,14 @@ var ( _ client.CloudOperationsClient = &Client{} ) -func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, clientVersion string) (*Client, error) { +var TemporalCloudAPIVersion = "2023-10-01-00" + +func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string) (*Client, error) { var cClient client.CloudOperationsClient var err error cClient, err = client.DialCloudOperationsClient(context.Background(), client.CloudOperationsClientOptions{ - Version: clientVersion, + Version: TemporalCloudAPIVersion, Credentials: client.NewAPIKeyStaticCredentials(apiKey), DisableTLS: allowInsecure, HostPort: addrStr, diff --git a/internal/provider/namespace_resource_test.go b/internal/provider/namespace_resource_test.go index a4d3681..e678448 100644 --- a/internal/provider/namespace_resource_test.go +++ b/internal/provider/namespace_resource_test.go @@ -72,7 +72,7 @@ func TestAccBasicNamespaceWithApiKeyAuth(t *testing.T) { config := func(name string, retention int) string { return fmt.Sprintf(` provider "temporalcloud" { - client_version = "2024-05-13-00" + } resource "temporalcloud_namespace" "terraform" { @@ -174,9 +174,7 @@ func TestAccNamespaceWithCodecServer(t *testing.T) { name := fmt.Sprintf("%s-%s", "tf-codec-server", randomString()) tmpl := template.Must(template.New("config").Parse(` provider "temporalcloud" { - {{ if .ApiKeyAuth }} - client_version = "2024-05-13-00" - {{ end }} + } resource "temporalcloud_namespace" "test" { @@ -250,7 +248,7 @@ PEM }), Check: func(s *terraform.State) error { id := s.RootModule().Resources["temporalcloud_namespace.test"].Primary.Attributes["id"] - conn := newConnection(t, "2023-10-01-00") + conn := newConnection(t) ns, err := conn.GetNamespace(context.Background(), &cloudservicev1.GetNamespaceRequest{ Namespace: id, }) @@ -279,7 +277,7 @@ PEM }), Check: func(s *terraform.State) error { id := s.RootModule().Resources["temporalcloud_namespace.test"].Primary.Attributes["id"] - conn := newConnection(t, "2023-10-01-00") + conn := newConnection(t) ns, err := conn.GetNamespace(context.Background(), &cloudservicev1.GetNamespaceRequest{ Namespace: id, }) @@ -308,7 +306,7 @@ PEM }), Check: func(s *terraform.State) error { id := s.RootModule().Resources["temporalcloud_namespace.test"].Primary.Attributes["id"] - conn := newConnection(t, "2024-05-13-00") + conn := newConnection(t) ns, err := conn.GetNamespace(context.Background(), &cloudservicev1.GetNamespaceRequest{ Namespace: id, }) @@ -338,7 +336,7 @@ PEM }), Check: func(s *terraform.State) error { id := s.RootModule().Resources["temporalcloud_namespace.test"].Primary.Attributes["id"] - conn := newConnection(t, "2023-10-01-00") + conn := newConnection(t) ns, err := conn.GetNamespace(context.Background(), &cloudservicev1.GetNamespaceRequest{ Namespace: id, }) @@ -508,21 +506,14 @@ PEM }) } -func newConnection(t *testing.T, clientVersion string) cloudservicev1.CloudServiceClient { +func newConnection(t *testing.T) cloudservicev1.CloudServiceClient { apiKey := os.Getenv("TEMPORAL_CLOUD_API_KEY") endpoint := os.Getenv("TEMPORAL_CLOUD_ENDPOINT") if endpoint == "" { endpoint = "saas-api.tmprl.cloud:443" } allowInsecure := os.Getenv("TEMPORAL_CLOUD_ALLOW_INSECURE") == "true" - if clientVersion == "" { - clientVersion = os.Getenv("TEMPORAL_CLOUD_CLIENT_VERSION") - if clientVersion == "" { - clientVersion = "2023-10-01-00" - } - } - - client, err := client.NewConnectionWithAPIKey(endpoint, allowInsecure, apiKey, clientVersion) + client, err := client.NewConnectionWithAPIKey(endpoint, allowInsecure, apiKey) if err != nil { t.Fatalf("Failed to create client: %v", err) } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index da6b9a5..a2a4f27 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -30,7 +30,6 @@ type TerraformCloudProviderModel struct { APIKey types.String `tfsdk:"api_key"` Endpoint types.String `tfsdk:"endpoint"` AllowInsecure types.Bool `tfsdk:"allow_insecure"` - ClientVersion types.String `tfsdk:"client_version"` } func (p *TerraformCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { @@ -70,10 +69,6 @@ in version control. We recommend passing credentials to this provider via enviro Description: "If set to True, it allows for an insecure connection to the Temporal Cloud API. This should never be set to 'true' in production and defaults to false.", Optional: true, }, - "client_version": schema.StringAttribute{ - Description: "The version of the Temporal Cloud API client to use. Defaults to `2023-10-01-00`. To create namespaces with API key authentication enabled, use `2024-05-13-00`.", - Optional: true, - }, }, } } @@ -110,14 +105,6 @@ func (p *TerraformCloudProvider) Configure(ctx context.Context, req provider.Con " Either apply the source of the value first, or statically set the allow_insecure flag via environment variable or in configuration.") } - if data.ClientVersion.IsUnknown() { - resp.Diagnostics.AddAttributeError( - path.Root("client_version"), - "Unknown Terraform Cloud Client Version", - "The provider cannot create a Terraform Cloud API client as there is an unknown configuration value for the Temporal Cloud Client Version."+ - " Either apply the source of the value first, or statically set the Client Version via environment variable or in configuration.") - } - apiKey := os.Getenv("TEMPORAL_CLOUD_API_KEY") if !data.APIKey.IsNull() { apiKey = data.APIKey.ValueString() @@ -136,15 +123,7 @@ func (p *TerraformCloudProvider) Configure(ctx context.Context, req provider.Con allowInsecure = data.AllowInsecure.ValueBool() } - clientVersion := "2023-10-01-00" - if os.Getenv("TEMPORAL_CLOUD_CLIENT_VERSION") != "" { - clientVersion = os.Getenv("TEMPORAL_CLOUD_CLIENT_VERSION") - } - if !data.ClientVersion.IsNull() { - clientVersion = data.ClientVersion.ValueString() - } - - client, err := client.NewConnectionWithAPIKey(endpoint, allowInsecure, apiKey, clientVersion) + client, err := client.NewConnectionWithAPIKey(endpoint, allowInsecure, apiKey) if err != nil { resp.Diagnostics.AddError("Failed to connect to Temporal Cloud API", err.Error()) return diff --git a/internal/provider/user_resource_test.go b/internal/provider/user_resource_test.go index 7bdac1a..9f55813 100644 --- a/internal/provider/user_resource_test.go +++ b/internal/provider/user_resource_test.go @@ -135,7 +135,7 @@ resource "temporalcloud_user" "terraform" { }), Check: func(state *terraform.State) error { id := state.RootModule().Resources["temporalcloud_user.terraform"].Primary.Attributes["id"] - conn := newConnection(t, "2023-10-01-00") + conn := newConnection(t) user, err := conn.GetUser(context.Background(), &cloudservicev1.GetUserRequest{ UserId: id, }) From 2b2fd212b8b4df229ecd74609bf026434a3ab7f5 Mon Sep 17 00:00:00 2001 From: Kshitij Wadhwa Date: Wed, 2 Oct 2024 13:38:11 -0700 Subject: [PATCH 5/5] upgrade temporal cloud api client version --- .../temporalcloud_namespace/resource.tf | 2 +- internal/client/client.go | 3 -- internal/provider/namespace_resource.go | 35 +++++++++---------- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/examples/resources/temporalcloud_namespace/resource.tf b/examples/resources/temporalcloud_namespace/resource.tf index a6fdee3..2b3a7a3 100644 --- a/examples/resources/temporalcloud_namespace/resource.tf +++ b/examples/resources/temporalcloud_namespace/resource.tf @@ -93,4 +93,4 @@ resource "temporalcloud_namespace" "terraform3" { regions = ["aws-us-east-1"] api_key_auth = true retention_days = 14 -} \ No newline at end of file +} diff --git a/internal/client/client.go b/internal/client/client.go index 6a4037c..7dfb39a 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -36,7 +36,6 @@ import ( "go.temporal.io/sdk/client" ) - var TemporalCloudAPIVersion = "2024-05-13-00" // Client is a client for the Temporal Cloud API. @@ -48,8 +47,6 @@ var ( _ client.CloudOperationsClient = &Client{} ) -var TemporalCloudAPIVersion = "2023-10-01-00" - func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string) (*Client, error) { var cClient client.CloudOperationsClient diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index 7f2b8c4..cfbbcda 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -204,6 +204,7 @@ func (r *namespaceResource) Schema(ctx context.Context, _ resource.SchemaRequest "api_key_auth": schema.BoolAttribute{ Description: "If true, Temporal Cloud will use API key authentication for this namespace. If false, mutual TLS (mTLS) authentication will be used.", Optional: true, + Computed: true, }, "codec_server": schema.SingleNestedAttribute{ Description: "A codec server is used by the Temporal Cloud UI to decode payloads for all users interacting with this namespace, even if the workflow history itself is encrypted.", @@ -298,19 +299,14 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque resp.Diagnostics.AddError("Namespace not configured with authentication. accepted_client_ca is required when API key authentication is not enabled (api_key_auth is not set to true).", "") return } - var mtlAuth *namespacev1.MtlsAuthSpec - mtlAuth = &namespacev1.MtlsAuthSpec{ - AcceptedClientCa: plan.AcceptedClientCA.ValueString(), - CertificateFilters: certFilters, + mtls := &namespacev1.MtlsAuthSpec{} + if plan.AcceptedClientCA.ValueString() != "" { + mtls.Enabled = true + mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() + mtls.CertificateFilters = certFilters } - mtls := &namespacev1.MtlsAuthSpec{} - if plan.AcceptedClientCA.ValueString() != "" { - mtls.Enabled = true - mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() - mtls.CertificateFilters = certFilters - } - spec.MtlsAuth = mtlAuth + spec.MtlsAuth = mtls } svcResp, err := r.client.CloudService().CreateNamespace(ctx, &cloudservicev1.CreateNamespaceRequest{ @@ -403,14 +399,15 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque resp.Diagnostics.AddError("Namespace not configured with authentication. accepted_client_ca is required when API key authentication is not enabled (api_key_auth is not set to true).", "") return } - mtls := &namespacev1.MtlsAuthSpec{} - if plan.AcceptedClientCA.ValueString() != "" { - mtls.Enabled = true - mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() - mtls.CertificateFilters = certFilters - } - - spec.MtlsAuth = mtlAuth + + mtls := &namespacev1.MtlsAuthSpec{} + if plan.AcceptedClientCA.ValueString() != "" { + mtls.Enabled = true + mtls.AcceptedClientCa = plan.AcceptedClientCA.ValueString() + mtls.CertificateFilters = certFilters + } + + spec.MtlsAuth = mtls } svcResp, err := r.client.CloudService().UpdateNamespace(ctx, &cloudservicev1.UpdateNamespaceRequest{