Skip to content

Commit 139899e

Browse files
Added support for db query logging update & delete resource (#124)
* Added support for db query logging update & delete * Use cluster id instead of cluster name
1 parent b10ea07 commit 139899e

File tree

2 files changed

+185
-71
lines changed

2 files changed

+185
-71
lines changed

managed/models.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ type DbQueryLoggingConfig struct {
374374
AccountID types.String `tfsdk:"account_id"`
375375
ProjectID types.String `tfsdk:"project_id"`
376376
ClusterID types.String `tfsdk:"cluster_id"`
377-
ClusterName types.String `tfsdk:"cluster_name"`
378377
IntegrationName types.String `tfsdk:"integration_name"`
379378
State types.String `tfsdk:"state"`
380379
ConfigID types.String `tfsdk:"config_id"`

managed/resource_db_query_logging.go

Lines changed: 185 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ func (r resourceDbQueryLoggingType) GetSchema(ctx context.Context) (tfsdk.Schema
2323
return tfsdk.Schema{
2424
Description: `The resource to manage DB query logging configuration for a cluster in YugabyteDB Aeon.`,
2525
Attributes: map[string]tfsdk.Attribute{
26-
"cluster_name": {
27-
Description: "Name of the cluster with which this DB query logging config will be associated.",
28-
Type: types.StringType,
29-
Required: true,
30-
},
3126
"integration_name": {
3227
Description: "Name of the integration for this DB query logging configuration.",
3328
Type: types.StringType,
@@ -46,10 +41,10 @@ func (r resourceDbQueryLoggingType) GetSchema(ctx context.Context) (tfsdk.Schema
4641
"cluster_id": {
4742
Description: "ID of the cluster with which this DB query logging config will be associated.",
4843
Type: types.StringType,
49-
Computed: true,
44+
Required: true,
5045
},
5146
"config_id": {
52-
Description: "ID of the DB query logging configuration.",
47+
Description: "ID of the DB query logging configuration. Created automatically when enabling DB query logs.",
5348
Type: types.StringType,
5449
Computed: true,
5550
},
@@ -60,8 +55,7 @@ func (r resourceDbQueryLoggingType) GetSchema(ctx context.Context) (tfsdk.Schema
6055
},
6156
"log_config": {
6257
Description: "The Log config.",
63-
Optional: true,
64-
Computed: true,
58+
Required: true,
6559
Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{
6660
"log_min_duration_statement": {
6761
Description: "Duration(in ms) of each completed statement to be logged if the statement ran for at least the specified amount of time.",
@@ -138,15 +132,23 @@ type resourceDbQueryLogging struct {
138132

139133
func getConfigFromPlan(ctx context.Context, plan tfsdk.Plan, config *DbQueryLoggingConfig) diag.Diagnostics {
140134
var diags diag.Diagnostics
141-
diags.Append(plan.GetAttribute(ctx, path.Root("cluster_name"), &config.ClusterName)...)
135+
diags.Append(plan.GetAttribute(ctx, path.Root("cluster_id"), &config.ClusterID)...)
142136
diags.Append(plan.GetAttribute(ctx, path.Root("integration_name"), &config.IntegrationName)...)
143137
diags.Append(plan.GetAttribute(ctx, path.Root("log_config"), &config.LogConfig)...)
144138
return diags
145139
}
146140

147-
func buildDbQueryLoggingSpec(config DbQueryLoggingConfig, integrationId string) (*openapiclient.PgLogExporterConfigSpec, error) {
148-
// Start with a default log config
149-
newLogConfig := openapiclient.NewPgLogExportConfigWithDefaults()
141+
func getConfigFromState(ctx context.Context, state tfsdk.State, config *DbQueryLoggingConfig) {
142+
state.GetAttribute(ctx, path.Root("account_id"), &config.AccountID)
143+
state.GetAttribute(ctx, path.Root("project_id"), &config.ProjectID)
144+
state.GetAttribute(ctx, path.Root("cluster_id"), &config.ClusterID)
145+
state.GetAttribute(ctx, path.Root("integration_name"), &config.IntegrationName)
146+
state.GetAttribute(ctx, path.Root("config_id"), &config.ConfigID)
147+
state.GetAttribute(ctx, path.Root("log_config"), &config.LogConfig)
148+
}
149+
150+
func buildDbQueryLoggingSpec(config DbQueryLoggingConfig, integrationId string, exportConfig *openapiclient.PgLogExportConfig) (*openapiclient.PgLogExporterConfigSpec, error) {
151+
newLogConfig := *exportConfig
150152

151153
// Update log config params, that are provided in tf file
152154
if config.LogConfig != nil {
@@ -155,6 +157,10 @@ func buildDbQueryLoggingSpec(config DbQueryLoggingConfig, integrationId string)
155157
newLogConfig.SetLogConnections(tfLogConfig.LogConnections.Value)
156158
}
157159

160+
if !tfLogConfig.DebugPrintPlan.IsNull() && !tfLogConfig.DebugPrintPlan.IsUnknown() {
161+
newLogConfig.SetDebugPrintPlan(tfLogConfig.DebugPrintPlan.Value)
162+
}
163+
158164
if !tfLogConfig.LogDisconnections.IsNull() && !tfLogConfig.LogDisconnections.IsUnknown() {
159165
newLogConfig.SetLogDisconnections(tfLogConfig.LogDisconnections.Value)
160166
}
@@ -198,27 +204,48 @@ func buildDbQueryLoggingSpec(config DbQueryLoggingConfig, integrationId string)
198204

199205
// Return the new PgLogExporterConfigSpec
200206
return &openapiclient.PgLogExporterConfigSpec{
201-
ExportConfig: *newLogConfig,
207+
ExportConfig: newLogConfig,
202208
ExporterId: integrationId,
203209
}, nil
204210
}
205211

206-
// Read latest state/config of a resource from Backend and convert it to model
207-
func resourceRead(ctx context.Context, accountId string, projectId string, clusterId string,
208-
clusterName string, integrationName string,
209-
apiClient *openapiclient.APIClient) (dbQueryLoggingConfig DbQueryLoggingConfig, readOK bool, errMsg string) {
210-
211-
// fetch log config from backend
212+
func getPgLogExporterConfig(ctx context.Context, accountId string, projectId string, clusterId string, apiClient *openapiclient.APIClient) (conf *openapiclient.PgLogExporterConfigData, ok bool, errMsg string) {
212213
specList, _, err := apiClient.ClusterApi.ListPgLogExporterConfigs(ctx, accountId, projectId, clusterId).Execute()
213214
if err != nil {
214-
return dbQueryLoggingConfig, false, GetApiErrorDetails(err)
215+
return nil, false, GetApiErrorDetails(err)
215216
}
216217

217-
if len(specList.GetData()) == 0 {
218-
return dbQueryLoggingConfig, false, fmt.Sprintf("No DB query logging config found for cluster %s", clusterName)
218+
if len(specList.GetData()) < 1 {
219+
return nil, false, "no DB query logging config found for the cluster"
219220
}
221+
return &specList.Data[0], true, ""
222+
}
220223

221-
spec := specList.Data[0]
224+
func getIntegrationId(ctx context.Context, accountId string, projectId string, integrationName string, apiClient *openapiclient.APIClient) (data *openapiclient.TelemetryProviderData, ok bool, errMsg string) {
225+
integrationConfig, _, err := apiClient.TelemetryProviderApi.
226+
ListTelemetryProviders(ctx, accountId, projectId).
227+
Name(integrationName).
228+
Execute()
229+
if err != nil {
230+
return data, false, GetApiErrorDetails(err)
231+
}
232+
233+
if len(integrationConfig.GetData()) < 1 {
234+
errMsg := fmt.Sprintf("Integration %s not found", integrationName)
235+
return nil, false, errMsg
236+
}
237+
return &integrationConfig.GetData()[0], true, ""
238+
}
239+
240+
// Read latest state/config of a resource from Backend and convert it to model
241+
func resourceRead(ctx context.Context, accountId string, projectId string, clusterId string,
242+
integrationName string,
243+
apiClient *openapiclient.APIClient) (dbQueryLoggingConfig DbQueryLoggingConfig, readOK bool, errMsg string) {
244+
245+
spec, ok, errMsg := getPgLogExporterConfig(ctx, accountId, projectId, clusterId, apiClient)
246+
if !ok {
247+
return dbQueryLoggingConfig, false, errMsg
248+
}
222249
exportConfig := spec.Spec.ExportConfig
223250

224251
// Initialize the LogConfig object from PgLogExportConfig
@@ -238,7 +265,6 @@ func resourceRead(ctx context.Context, accountId string, projectId string, clust
238265
AccountID: types.String{Value: accountId},
239266
ProjectID: types.String{Value: projectId},
240267
ClusterID: types.String{Value: clusterId},
241-
ClusterName: types.String{Value: clusterName},
242268
IntegrationName: types.String{Value: integrationName},
243269
State: types.String{Value: string(spec.Info.State)},
244270
ConfigID: types.String{Value: spec.Info.Id},
@@ -248,27 +274,16 @@ func resourceRead(ctx context.Context, accountId string, projectId string, clust
248274
return dbQueryLoggingConfig, true, ""
249275
}
250276

251-
func getConfigFromState(ctx context.Context, state tfsdk.State, config *DbQueryLoggingConfig) {
252-
state.GetAttribute(ctx, path.Root("account_id"), &config.AccountID)
253-
state.GetAttribute(ctx, path.Root("project_id"), &config.ProjectID)
254-
state.GetAttribute(ctx, path.Root("cluster_name"), &config.ClusterName)
255-
state.GetAttribute(ctx, path.Root("cluster_id"), &config.ClusterID)
256-
state.GetAttribute(ctx, path.Root("integration_name"), &config.IntegrationName)
257-
state.GetAttribute(ctx, path.Root("config_id"), &config.ConfigID)
258-
}
259-
260277
func (r resourceDbQueryLogging) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
261278
var state DbQueryLoggingConfig
262-
263279
getConfigFromState(ctx, req.State, &state)
264280
apiClient := r.p.client
265281
accountId := state.AccountID.Value
266282
projectId := state.ProjectID.Value
267283
clusterId := state.ClusterID.Value
268-
clusterName := state.ClusterName.Value
269284
integrationName := state.IntegrationName.Value
270285

271-
dbqlConfig, readOK, message := resourceRead(ctx, accountId, projectId, clusterId, clusterName, integrationName, apiClient)
286+
dbqlConfig, readOK, message := resourceRead(ctx, accountId, projectId, clusterId, integrationName, apiClient)
272287
if !readOK {
273288
resp.Diagnostics.AddError("Unable to read the state of Db Query log configuration associated with the cluster", message)
274289
return
@@ -282,17 +297,134 @@ func (r resourceDbQueryLogging) Read(ctx context.Context, req tfsdk.ReadResource
282297
}
283298

284299
func (r resourceDbQueryLogging) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
285-
resp.Diagnostics.AddError(
286-
"Unsupported Operation",
287-
"Update is not currently supported.",
288-
)
300+
var planConfig DbQueryLoggingConfig
301+
resp.Diagnostics.Append(getConfigFromPlan(ctx, req.Plan, &planConfig)...)
302+
if resp.Diagnostics.HasError() {
303+
tflog.Debug(ctx, "Error while getting the plan for the Db query logging config")
304+
return
305+
}
306+
integrationName := planConfig.IntegrationName.Value
307+
308+
apiClient := r.p.client
309+
var stateConfig DbQueryLoggingConfig
310+
getConfigFromState(ctx, req.State, &stateConfig)
311+
accountId := stateConfig.AccountID.Value
312+
projectId := stateConfig.ProjectID.Value
313+
clusterId := stateConfig.ClusterID.Value
314+
configId := stateConfig.ConfigID.Value
315+
316+
if planConfig.ClusterID != stateConfig.ClusterID {
317+
errMsg := "Field cluster_id cannot be changed after resource creation"
318+
resp.Diagnostics.AddError(errMsg, errMsg)
319+
return
320+
}
321+
322+
spec, ok, errMsg := getPgLogExporterConfig(ctx, accountId, projectId, clusterId, apiClient)
323+
if !ok {
324+
resp.Diagnostics.AddError("Unable to fetch DB query logging config", errMsg)
325+
return
326+
}
327+
328+
integrationId := ""
329+
if planConfig.IntegrationName != stateConfig.IntegrationName {
330+
integrationConfig, ok, errMsg := getIntegrationId(ctx, accountId, projectId, integrationName, apiClient)
331+
if !ok {
332+
resp.Diagnostics.AddError("Unable to fetch integration details for: "+integrationName, errMsg)
333+
return
334+
}
335+
integrationId = integrationConfig.Info.Id
336+
} else {
337+
integrationId = spec.Spec.ExporterId
338+
}
339+
// Use planConfig provided in tf file to build new API Pg log exporter config spec
340+
apiConfigSpec, err := buildDbQueryLoggingSpec(planConfig, integrationId, &spec.Spec.ExportConfig)
341+
if err != nil {
342+
resp.Diagnostics.AddError("Unable to update DB query logging config", GetApiErrorDetails(err))
343+
return
344+
}
345+
346+
_, _, err = apiClient.ClusterApi.UpdatePgLogExporterConfig(ctx, accountId, projectId, clusterId, configId).PgLogExporterConfigSpec(*apiConfigSpec).Execute()
347+
if err != nil {
348+
resp.Diagnostics.AddError(fmt.Sprintf("Unable to update DB query logging config for cluster %s", clusterId), GetApiErrorDetails(err))
349+
return
350+
}
351+
352+
retryPolicy := retry.NewConstant(10 * time.Second)
353+
retryPolicy = retry.WithMaxDuration(2400*time.Second, retryPolicy)
354+
err = retry.Do(ctx, retryPolicy, func(ctx context.Context) error {
355+
asState, readInfoOK, message := getTaskState(accountId, projectId, clusterId, openapiclient.ENTITYTYPEENUM_CLUSTER, openapiclient.TASKTYPEENUM_EDIT_DATABASE_QUERY_LOGGING, apiClient, ctx)
356+
if readInfoOK {
357+
if asState == string(openapiclient.TASKACTIONSTATEENUM_SUCCEEDED) {
358+
return nil
359+
}
360+
if asState == string(openapiclient.TASKACTIONSTATEENUM_FAILED) {
361+
return fmt.Errorf("failed to update DB query log config")
362+
}
363+
} else {
364+
return retry.RetryableError(errors.New("unable to check DB query log config update status: " + message))
365+
}
366+
return retry.RetryableError(errors.New("DB query log config is being updated"))
367+
})
368+
369+
if err != nil {
370+
errorSummary := fmt.Sprintf("Unable to update DB query log config for cluster: %s", clusterId)
371+
resp.Diagnostics.AddError(errorSummary, "The operation timed out waiting for DB query log config update operation.")
372+
return
373+
}
374+
375+
planConfig.ConfigID.Value = configId
376+
377+
dbqlConfig, readOK, readErrMsg := resourceRead(ctx, accountId, projectId, clusterId, integrationName, apiClient)
378+
if !readOK {
379+
resp.Diagnostics.AddError("Unable to read the state of Db Query log config ", readErrMsg)
380+
return
381+
}
382+
383+
diags := resp.State.Set(ctx, &dbqlConfig)
384+
resp.Diagnostics.Append(diags...)
385+
if resp.Diagnostics.HasError() {
386+
return
387+
}
289388
}
290389

291390
func (r resourceDbQueryLogging) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
292-
resp.Diagnostics.AddError(
293-
"Unsupported Operation",
294-
"Delete is not currently supported.",
295-
)
391+
apiClient := r.p.client
392+
var state DbQueryLoggingConfig
393+
getConfigFromState(ctx, req.State, &state)
394+
accountId := state.AccountID.Value
395+
projectId := state.ProjectID.Value
396+
clusterId := state.ClusterID.Value
397+
configId := state.ConfigID.Value
398+
399+
_, err := apiClient.ClusterApi.RemovePgLogExporterConfig(ctx, accountId, projectId, clusterId, configId).Execute()
400+
if err != nil {
401+
resp.Diagnostics.AddError(fmt.Sprintf("Unable to remove DB query logging config for cluster: %s", clusterId), GetApiErrorDetails(err))
402+
return
403+
}
404+
405+
retryPolicy := retry.NewConstant(10 * time.Second)
406+
retryPolicy = retry.WithMaxDuration(2400*time.Second, retryPolicy)
407+
err = retry.Do(ctx, retryPolicy, func(ctx context.Context) error {
408+
asState, readInfoOK, message := getTaskState(accountId, projectId, clusterId, openapiclient.ENTITYTYPEENUM_CLUSTER, openapiclient.TASKTYPEENUM_DISABLE_DATABASE_QUERY_LOGGING, apiClient, ctx)
409+
if readInfoOK {
410+
if asState == string(openapiclient.TASKACTIONSTATEENUM_SUCCEEDED) {
411+
return nil
412+
}
413+
if asState == string(openapiclient.TASKACTIONSTATEENUM_FAILED) {
414+
return ErrFailedTask
415+
}
416+
} else {
417+
return retry.RetryableError(errors.New("Unable to check status for DB query logging removal task: " + message))
418+
}
419+
return retry.RetryableError(errors.New("DB Query log configuration is being removed from the cluster"))
420+
})
421+
422+
if err != nil {
423+
resp.Diagnostics.AddError("Unable to remove Db Logging config from the cluster ", "The operation timed out waiting for DB Query Logging removal to complete.")
424+
return
425+
}
426+
427+
resp.State.RemoveResource(ctx)
296428
}
297429

298430
func (r resourceDbQueryLogging) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
@@ -331,38 +463,21 @@ func (r resourceDbQueryLogging) Create(ctx context.Context, req tfsdk.CreateReso
331463
return
332464
}
333465

334-
var clusterId string
466+
var clusterId = config.ClusterID.Value
335467
var integrationId string
336468

337-
clusterName := config.ClusterName.Value
338469
integrationName := config.IntegrationName.Value
339-
clusterData, err := GetClusterByNameorID(accountId, projectId, "", clusterName, apiClient)
340-
if err != nil {
341-
resp.Diagnostics.AddError("Unable to fetch cluster details for cluster: "+clusterName, GetApiErrorDetails(err))
342-
return
343-
}
344-
clusterId = clusterData.Info.Id
345470

346-
integrationConfig, _, err := apiClient.TelemetryProviderApi.
347-
ListTelemetryProviders(context.Background(), accountId, projectId).
348-
Name(integrationName).
349-
Execute()
350-
351-
if err != nil {
352-
resp.Diagnostics.AddError("Unable to fetch integration details for integration: "+integrationName, GetApiErrorDetails(err))
353-
return
354-
}
355-
356-
if len(integrationConfig.GetData()) < 1 {
357-
message := fmt.Sprintf("Integration %s not found", integrationName)
358-
resp.Diagnostics.AddError(message, message)
471+
integrationConfig, ok, errMsg := getIntegrationId(ctx, accountId, projectId, integrationName, apiClient)
472+
if !ok {
473+
resp.Diagnostics.AddError("Unable to fetch integration details for: "+integrationName, errMsg)
359474
return
360475
}
361-
integrationId = integrationConfig.GetData()[0].Info.Id
476+
integrationId = integrationConfig.Info.Id
362477

363-
dbQueryLoggingConfigSpec, err := buildDbQueryLoggingSpec(config, integrationId)
478+
dbQueryLoggingConfigSpec, err := buildDbQueryLoggingSpec(config, integrationId, openapiclient.NewPgLogExportConfigWithDefaults())
364479
if err != nil {
365-
resp.Diagnostics.AddWarning("Unable to build DB query logging config spec", GetApiErrorDetails(err))
480+
tflog.Warn(ctx, "Unable to build DB query logging config spec"+GetApiErrorDetails(err))
366481
resp.Diagnostics.AddError("Encountered error while enabling DB Query Logging", GetApiErrorDetails(err))
367482
return
368483
}
@@ -401,7 +516,7 @@ func (r resourceDbQueryLogging) Create(ctx context.Context, req tfsdk.CreateReso
401516
}
402517

403518
dbQueryLoggingConfig, readOK, readErrMsg := resourceRead(ctx, accountId, projectId,
404-
clusterId, clusterName, integrationName, apiClient)
519+
clusterId, integrationName, apiClient)
405520
if !readOK {
406521
resp.Diagnostics.AddError("Unable to read the state of Db Query log config for the cluster ", readErrMsg)
407522
return

0 commit comments

Comments
 (0)