Skip to content

Commit eb5ed58

Browse files
committed
feat(provider/big_query_source): use correct inline structure for service account keys
1 parent c1a2622 commit eb5ed58

File tree

10 files changed

+202
-18
lines changed

10 files changed

+202
-18
lines changed

docs/resources/big_query_source.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,19 @@ Required:
5656

5757
Optional:
5858

59-
- `service_account_key` (String, Sensitive)
59+
- `service_account_key` (Attributes) (see [below for nested schema](#nestedatt--credentials--service_account_key))
60+
61+
<a id="nestedatt--credentials--service_account_key"></a>
62+
### Nested Schema for `credentials.service_account_key`
63+
64+
Required:
65+
66+
- `client_email` (String)
67+
- `client_id` (String)
68+
- `private_key` (String, Sensitive)
69+
- `private_key_id` (String)
70+
- `project_id` (String)
71+
6072

6173

6274
<a id="nestedatt--connection_details"></a>

internal/provider/big_query_source_model.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ type BigQuerySourceModel struct {
1717

1818
//nolint:recvcheck
1919
type BigQuerySourceCredentials struct {
20-
ProjectID types.String `tfsdk:"project_id"`
21-
Location types.String `tfsdk:"location"`
22-
ServiceAccountKey types.String `tfsdk:"service_account_key"`
20+
ProjectID types.String `tfsdk:"project_id"`
21+
Location types.String `tfsdk:"location"`
22+
ServiceAccountKey TypedObject[BigQuerySourceCredentialsServiceAccountKey] `tfsdk:"service_account_key"`
23+
}
24+
25+
type BigQuerySourceCredentialsServiceAccountKey struct {
26+
ProjectID types.String `tfsdk:"project_id"`
27+
PrivateKeyID types.String `tfsdk:"private_key_id"`
28+
PrivateKey types.String `tfsdk:"private_key"`
29+
ClientEmail types.String `tfsdk:"client_email"`
30+
ClientID types.String `tfsdk:"client_id"`
2331
}
2432

2533
type BigQuerySourceConnectionDetails struct {

internal/provider/big_query_source_model_request.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,35 @@ func (c BigQuerySourceCredentials) Encode(enc *jx.Encoder) {
6363
e.Str(c.Location.ValueString())
6464
})
6565

66-
serviceAccountKey := c.ServiceAccountKey.ValueString()
67-
if serviceAccountKey != "" {
66+
serviceAccountKey, serviceAccountKeyOk := c.ServiceAccountKey.GetValue()
67+
if serviceAccountKeyOk {
6868
enc.Field("service_account_key", func(e *jx.Encoder) {
69-
e.Str(serviceAccountKey)
69+
serviceAccountKey.Encode(e)
7070
})
7171
}
7272
})
7373
}
74+
75+
func (c BigQuerySourceCredentialsServiceAccountKey) Encode(enc *jx.Encoder) {
76+
enc.Obj(func(enc *jx.Encoder) {
77+
enc.Field("project_id", func(e *jx.Encoder) {
78+
e.Str(c.ProjectID.ValueString())
79+
})
80+
81+
enc.Field("private_key_id", func(e *jx.Encoder) {
82+
e.Str(c.PrivateKeyID.ValueString())
83+
})
84+
85+
enc.Field("private_key", func(e *jx.Encoder) {
86+
e.Str(c.PrivateKey.ValueString())
87+
})
88+
89+
enc.Field("client_email", func(e *jx.Encoder) {
90+
e.Str(c.ClientEmail.ValueString())
91+
})
92+
93+
enc.Field("client_id", func(e *jx.Encoder) {
94+
e.Str(c.ClientID.ValueString())
95+
})
96+
})
97+
}

internal/provider/big_query_source_resource.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,38 @@ func (r *bigQuerySourceResource) MoveState(ctx context.Context) []resource.State
6666
return
6767
}
6868

69+
type sourceCredentialsServiceAccountKeyModel struct {
70+
ProjectID *string `json:"project_id"`
71+
PrivateKeyID *string `json:"private_key_id"`
72+
PrivateKey *string `json:"private_key"`
73+
ClientEmail *string `json:"client_email"`
74+
ClientID *string `json:"client_id"`
75+
}
76+
6977
type sourceCredentialsModel struct {
70-
ProjectID *string `json:"project_id"`
71-
Location *string `json:"location"`
72-
ServiceAccountKey *string `json:"service_account_key"`
78+
ProjectID *string `json:"project_id"`
79+
Location *string `json:"location"`
80+
ServiceAccountKey *sourceCredentialsServiceAccountKeyModel `json:"service_account_key"`
7381
}
7482

7583
sourceCredentials := sourceCredentialsModel{}
7684
resp.Diagnostics.Append(sourceModel.Credentials.Unmarshal(&sourceCredentials)...)
7785

7886
bigQuerySourceCredentials := BigQuerySourceCredentials{
79-
ProjectID: types.StringPointerValue(sourceCredentials.ProjectID),
80-
Location: types.StringPointerValue(sourceCredentials.Location),
81-
ServiceAccountKey: types.StringPointerValue(sourceCredentials.ServiceAccountKey),
87+
ProjectID: types.StringPointerValue(sourceCredentials.ProjectID),
88+
Location: types.StringPointerValue(sourceCredentials.Location),
89+
}
90+
91+
if sourceCredentials.ServiceAccountKey != nil {
92+
serviceAccountKey := NewTypedObject(BigQuerySourceCredentialsServiceAccountKey{
93+
ProjectID: types.StringPointerValue(sourceCredentials.ServiceAccountKey.ProjectID),
94+
PrivateKeyID: types.StringPointerValue(sourceCredentials.ServiceAccountKey.PrivateKeyID),
95+
PrivateKey: types.StringPointerValue(sourceCredentials.ServiceAccountKey.PrivateKey),
96+
ClientEmail: types.StringPointerValue(sourceCredentials.ServiceAccountKey.ClientEmail),
97+
ClientID: types.StringPointerValue(sourceCredentials.ServiceAccountKey.ClientID),
98+
})
99+
100+
bigQuerySourceCredentials.ServiceAccountKey = serviceAccountKey
82101
}
83102

84103
type sourceConnectionDetailsModel struct {

internal/provider/big_query_source_resource_schema.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,39 @@ func BigQuerySourceCredentialsResourceSchema(ctx context.Context) schema.Attribu
4040
}
4141
}
4242

43-
func BigQuerySourceCredentialsResourceSchemaAttributes(_ context.Context) map[string]schema.Attribute {
43+
func BigQuerySourceCredentialsResourceSchemaAttributes(ctx context.Context) map[string]schema.Attribute {
4444
return map[string]schema.Attribute{
4545
"project_id": schema.StringAttribute{
4646
Required: true,
4747
},
4848
"location": schema.StringAttribute{
4949
Required: true,
5050
},
51-
"service_account_key": schema.StringAttribute{
52-
Optional: true,
51+
"service_account_key": schema.SingleNestedAttribute{
52+
Optional: true,
53+
Attributes: BigQuerySourceCredentialsServiceAccountKeyResourceSchemaAttributes(ctx),
54+
CustomType: NewTypedObjectNull[BigQuerySourceCredentialsServiceAccountKey]().CustomType(ctx),
55+
},
56+
}
57+
}
58+
59+
func BigQuerySourceCredentialsServiceAccountKeyResourceSchemaAttributes(_ context.Context) map[string]schema.Attribute {
60+
return map[string]schema.Attribute{
61+
"project_id": schema.StringAttribute{
62+
Required: true,
63+
},
64+
"private_key_id": schema.StringAttribute{
65+
Required: true,
66+
},
67+
"private_key": schema.StringAttribute{
5368
Sensitive: true,
69+
Required: true,
70+
},
71+
"client_email": schema.StringAttribute{
72+
Required: true,
73+
},
74+
"client_id": schema.StringAttribute{
75+
Required: true,
5476
},
5577
}
5678
}

internal/provider/big_query_source_resource_test.go

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func TestAccBigQuerySourceResourceCreateUpdateDelete(t *testing.T) {
102102
ConfigDirectory: config.TestNameDirectory(),
103103
ConfigVariables: config.Variables{
104104
"source_label": config.StringVariable("Test Source"),
105-
"source_credentials": config.MapVariable(map[string]config.Variable{
105+
"source_credentials": config.ObjectVariable(map[string]config.Variable{
106106
"project_id": config.StringVariable("project-id"),
107107
"location": config.StringVariable("US"),
108108
}),
@@ -125,9 +125,16 @@ func TestAccBigQuerySourceResourceCreateUpdateDelete(t *testing.T) {
125125
ConfigDirectory: config.TestNameDirectory(),
126126
ConfigVariables: config.Variables{
127127
"source_label": config.StringVariable("Test Source (updated)"),
128-
"source_credentials": config.MapVariable(map[string]config.Variable{
128+
"source_credentials": config.ObjectVariable(map[string]config.Variable{
129129
"project_id": config.StringVariable("project-id"),
130130
"location": config.StringVariable("US"),
131+
"service_account_key": config.ObjectVariable(map[string]config.Variable{
132+
"project_id": config.StringVariable("project-id"),
133+
"private_key_id": config.StringVariable("private-key-id"),
134+
"private_key": config.StringVariable("private-key"),
135+
"client_id": config.StringVariable("client-id"),
136+
"client_email": config.StringVariable("client-email"),
137+
}),
131138
}),
132139
},
133140
ConfigPlanChecks: resource.ConfigPlanChecks{
@@ -197,3 +204,65 @@ func TestAccBigQuerySourceResourceMovedFromSource(t *testing.T) {
197204
},
198205
})
199206
}
207+
208+
//nolint:paralleltest
209+
func TestAccBigQuerySourceResourceMovedFromSourceWithServiceAccountKey(t *testing.T) {
210+
server, err := cmt.NewCensusManagementServer()
211+
require.NoError(t, err)
212+
213+
configVariables := config.Variables{
214+
"source_label": config.StringVariable("Test Source"),
215+
"source_credentials": config.ObjectVariable(map[string]config.Variable{
216+
"project_id": config.StringVariable("project-id"),
217+
"location": config.StringVariable("US"),
218+
"service_account_key": config.ObjectVariable(map[string]config.Variable{
219+
"project_id": config.StringVariable("project-id"),
220+
"private_key_id": config.StringVariable("private-key-id"),
221+
"private_key": config.StringVariable("private-key"),
222+
"client_id": config.StringVariable("client-id"),
223+
"client_email": config.StringVariable("client-email"),
224+
}),
225+
}),
226+
}
227+
228+
ProviderMockedResourceTest(t, server, resource.TestCase{
229+
Steps: []resource.TestStep{
230+
{
231+
ConfigDirectory: config.TestStepDirectory(),
232+
ConfigVariables: configVariables,
233+
ConfigPlanChecks: resource.ConfigPlanChecks{
234+
PreApply: []plancheck.PlanCheck{
235+
plancheck.ExpectResourceAction("censusworkspace_source.test", plancheck.ResourceActionCreate),
236+
plancheck.ExpectUnknownValue("censusworkspace_source.test", tfjsonpath.New("id")),
237+
plancheck.ExpectKnownValue("censusworkspace_source.test", tfjsonpath.New("label"), knownvalue.StringExact("Test Source")),
238+
},
239+
PostApplyPostRefresh: []plancheck.PlanCheck{
240+
plancheck.ExpectKnownValue("censusworkspace_source.test", tfjsonpath.New("last_test_succeeded"), knownvalue.Null()),
241+
},
242+
},
243+
},
244+
{
245+
ConfigDirectory: config.TestStepDirectory(),
246+
ConfigVariables: configVariables,
247+
248+
ConfigPlanChecks: resource.ConfigPlanChecks{
249+
PreApply: []plancheck.PlanCheck{
250+
plancheck.ExpectEmptyPlan(),
251+
plancheck.ExpectResourceAction("censusworkspace_big_query_source.test", plancheck.ResourceActionNoop),
252+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("id"), knownvalue.NotNull()),
253+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("label"), knownvalue.StringExact("Test Source")),
254+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("name"), knownvalue.NotNull()),
255+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("credentials").AtMapKey("project_id"), knownvalue.StringExact("project-id")),
256+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("credentials").AtMapKey("location"), knownvalue.StringExact("US")),
257+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("credentials").AtMapKey("service_account_key").AtMapKey("private_key_id"), knownvalue.StringExact("private-key-id")),
258+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("credentials").AtMapKey("service_account_key").AtMapKey("client_email"), knownvalue.StringExact("client-email")),
259+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("connection_details"), knownvalue.NotNull()),
260+
},
261+
PostApplyPostRefresh: []plancheck.PlanCheck{
262+
plancheck.ExpectKnownValue("censusworkspace_big_query_source.test", tfjsonpath.New("last_test_succeeded"), knownvalue.Null()),
263+
},
264+
},
265+
},
266+
},
267+
})
268+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resource "censusworkspace_source" "test" {
2+
type = "big_query"
3+
label = var.source_label
4+
5+
credentials = jsonencode(var.source_credentials)
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
variable "source_label" {
2+
type = string
3+
default = null
4+
}
5+
6+
variable "source_credentials" {
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
moved {
2+
from = censusworkspace_source.test
3+
to = censusworkspace_big_query_source.test
4+
}
5+
6+
resource "censusworkspace_big_query_source" "test" {
7+
label = var.source_label
8+
9+
credentials = var.source_credentials
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
variable "source_label" {
2+
type = string
3+
default = null
4+
}
5+
6+
variable "source_credentials" {
7+
}

0 commit comments

Comments
 (0)