Skip to content

Commit 6a18947

Browse files
Fix issue #12883 (#8738) (#15828)
* Fix issue #12883 Make one CloudResourceManager call per monitored_project terraform resource rather than per (monitored_project * "sibling" projects) * Add comment * Correct build errors * Fix build errors * Add debug logs * Fix printf * Fix match between TF resource and API response * Fix from non-matching to matching condition * Correct documentation * Correct documentation * Fix go build issues * Convert projectNumber to string * Use correct string conversion * Move comment * Add debug logs to monitored project encoder * correct delete_url Signed-off-by: Modular Magician <[email protected]>
1 parent e207472 commit 6a18947

File tree

3 files changed

+44
-89
lines changed

3 files changed

+44
-89
lines changed

.changelog/8738.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
monitoring: fixed scaling issues when deploying terraform changes with many `google_monitoring_monitored_project`
3+
```

google/services/monitoring/resource_monitoring_monitored_project.go

+40-88
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"log"
2424
"reflect"
25+
"strconv"
2526
"strings"
2627
"time"
2728

@@ -116,7 +117,7 @@ func resourceMonitoringMonitoredProjectCreate(d *schema.ResourceData, meta inter
116117
}
117118

118119
obj := make(map[string]interface{})
119-
nameProp, err := expandNestedMonitoringMonitoredProjectName(d.Get("name"), d, config)
120+
nameProp, err := expandMonitoringMonitoredProjectName(d.Get("name"), d, config)
120121
if err != nil {
121122
return err
122123
} else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
@@ -208,18 +209,6 @@ func resourceMonitoringMonitoredProjectRead(d *schema.ResourceData, meta interfa
208209
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("MonitoringMonitoredProject %q", d.Id()))
209210
}
210211

211-
res, err = flattenNestedMonitoringMonitoredProject(d, meta, res)
212-
if err != nil {
213-
return err
214-
}
215-
216-
if res == nil {
217-
// Object isn't there any more - remove it from the state.
218-
log.Printf("[DEBUG] Removing MonitoringMonitoredProject because it couldn't be matched.")
219-
d.SetId("")
220-
return nil
221-
}
222-
223212
res, err = resourceMonitoringMonitoredProjectDecoder(d, meta, res)
224213
if err != nil {
225214
return err
@@ -232,10 +221,10 @@ func resourceMonitoringMonitoredProjectRead(d *schema.ResourceData, meta interfa
232221
return nil
233222
}
234223

235-
if err := d.Set("name", flattenNestedMonitoringMonitoredProjectName(res["name"], d, config)); err != nil {
224+
if err := d.Set("name", flattenMonitoringMonitoredProjectName(res["name"], d, config)); err != nil {
236225
return fmt.Errorf("Error reading MonitoredProject: %s", err)
237226
}
238-
if err := d.Set("create_time", flattenNestedMonitoringMonitoredProjectCreateTime(res["createTime"], d, config)); err != nil {
227+
if err := d.Set("create_time", flattenMonitoringMonitoredProjectCreateTime(res["createTime"], d, config)); err != nil {
239228
return fmt.Errorf("Error reading MonitoredProject: %s", err)
240229
}
241230

@@ -251,7 +240,7 @@ func resourceMonitoringMonitoredProjectDelete(d *schema.ResourceData, meta inter
251240

252241
billingProject := ""
253242

254-
url, err := tpgresource.ReplaceVars(d, config, "{{MonitoringBasePath}}v1/locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}}")
243+
url, err := tpgresource.ReplaceVars(d, config, "{{MonitoringBasePath}}v1/{{name}}")
255244
if err != nil {
256245
return err
257246
}
@@ -308,107 +297,70 @@ func resourceMonitoringMonitoredProjectImport(d *schema.ResourceData, meta inter
308297
return []*schema.ResourceData{d}, nil
309298
}
310299

311-
func flattenNestedMonitoringMonitoredProjectName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
300+
func flattenMonitoringMonitoredProjectName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
312301
return v
313302
}
314303

315-
func flattenNestedMonitoringMonitoredProjectCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
304+
func flattenMonitoringMonitoredProjectCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
316305
return v
317306
}
318307

319-
func expandNestedMonitoringMonitoredProjectName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
308+
func expandMonitoringMonitoredProjectName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
320309
return v, nil
321310
}
322311

323312
func resourceMonitoringMonitoredProjectEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
324313
name := d.Get("name").(string)
314+
log.Printf("[DEBUG] Encoded monitored project name: %s", name)
325315
name = tpgresource.GetResourceNameFromSelfLink(name)
316+
log.Printf("[DEBUG] Encoded monitored project resource name: %s", name)
326317
d.Set("name", name)
327318
metricsScope := d.Get("metrics_scope").(string)
319+
log.Printf("[DEBUG] Encoded monitored project metricsScope: %s", metricsScope)
328320
metricsScope = tpgresource.GetResourceNameFromSelfLink(metricsScope)
321+
log.Printf("[DEBUG] Encoded monitored project metricsScope resource name: %s", metricsScope)
329322
d.Set("metrics_scope", metricsScope)
330323
obj["name"] = fmt.Sprintf("locations/global/metricsScopes/%s/projects/%s", metricsScope, name)
331324
return obj, nil
332325
}
333326

334-
func flattenNestedMonitoringMonitoredProject(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
335-
var v interface{}
336-
var ok bool
337-
338-
v, ok = res["monitoredProjects"]
339-
if !ok || v == nil {
340-
return nil, nil
341-
}
342-
343-
switch v.(type) {
344-
case []interface{}:
345-
break
346-
case map[string]interface{}:
347-
// Construct list out of single nested resource
348-
v = []interface{}{v}
349-
default:
350-
return nil, fmt.Errorf("expected list or map for value monitoredProjects. Actual value: %v", v)
351-
}
327+
func resourceMonitoringMonitoredProjectDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
328+
// terraform resource config
329+
config := meta.(*transport_tpg.Config)
352330

353-
_, item, err := resourceMonitoringMonitoredProjectFindNestedObjectInList(d, meta, v.([]interface{}))
354-
if err != nil {
355-
return nil, err
356-
}
357-
return item, nil
358-
}
331+
// The API returns all monitored projects
332+
monitoredProjects, _ := res["monitoredProjects"].([]interface{})
359333

360-
func resourceMonitoringMonitoredProjectFindNestedObjectInList(d *schema.ResourceData, meta interface{}, items []interface{}) (index int, item map[string]interface{}, err error) {
361-
expectedName, err := expandNestedMonitoringMonitoredProjectName(d.Get("name"), d, meta.(*transport_tpg.Config))
362-
if err != nil {
363-
return -1, nil, err
334+
// Convert configured terraform monitored_project resource name to a ProjectNumber
335+
expectedProject, configProjectErr := config.NewResourceManagerClient(config.UserAgent).Projects.Get(d.Get("name").(string)).Do()
336+
if configProjectErr != nil {
337+
return nil, configProjectErr
364338
}
365-
expectedFlattenedName := flattenNestedMonitoringMonitoredProjectName(expectedName, d, meta.(*transport_tpg.Config))
339+
expectedProjectNumber := strconv.FormatInt(expectedProject.ProjectNumber, 10)
366340

367-
// Search list for this resource.
368-
for idx, itemRaw := range items {
369-
if itemRaw == nil {
370-
continue
371-
}
372-
item := itemRaw.(map[string]interface{})
373-
374-
// Decode list item before comparing.
375-
item, err := resourceMonitoringMonitoredProjectDecoder(d, meta, item)
376-
if err != nil {
377-
return -1, nil, err
378-
}
341+
log.Printf("[DEBUG] Scanning for ProjectNumber: %s.", expectedProjectNumber)
379342

380-
itemName := flattenNestedMonitoringMonitoredProjectName(item["name"], d, meta.(*transport_tpg.Config))
381-
// IsEmptyValue check so that if one is nil and the other is "", that's considered a match
382-
if !(tpgresource.IsEmptyValue(reflect.ValueOf(itemName)) && tpgresource.IsEmptyValue(reflect.ValueOf(expectedFlattenedName))) && !reflect.DeepEqual(itemName, expectedFlattenedName) {
383-
log.Printf("[DEBUG] Skipping item with name= %#v, looking for %#v)", itemName, expectedFlattenedName)
343+
// Iterate through the list of monitoredProjects to make sure one matches the configured monitored_project
344+
for _, monitoredProjectRaw := range monitoredProjects {
345+
if monitoredProjectRaw == nil {
384346
continue
385347
}
386-
log.Printf("[DEBUG] Found item for resource %q: %#v)", d.Id(), item)
387-
return idx, item, nil
388-
}
389-
return -1, nil, nil
390-
}
391-
func resourceMonitoringMonitoredProjectDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
392-
config := meta.(*transport_tpg.Config)
393-
394-
expectedName, _ := expandNestedMonitoringMonitoredProjectName(d.Get("name"), d, config)
395-
expectedFlattenedName := flattenNestedMonitoringMonitoredProjectName(expectedName, d, config)
396-
_, isNumErr := tpgresource.StringToFixed64(expectedFlattenedName.(string))
397-
expectProjectNumber := isNumErr == nil
398-
399-
name := res["name"].(string)
400-
name = tpgresource.GetResourceNameFromSelfLink(name)
401-
402-
if expectProjectNumber {
403-
res["name"] = name
404-
} else if name != "" {
405-
project, err := config.NewResourceManagerClient(config.UserAgent).Projects.Get(name).Do()
406-
if err != nil {
407-
return nil, err
348+
monitoredProject := monitoredProjectRaw.(map[string]interface{})
349+
350+
// MonitoredProject names have the format locations/global/metricsScopes/[metricScopeProjectNumber]/projects/[projectNumber]
351+
monitoredProjectName := monitoredProject["name"]
352+
353+
// `res` contains the MonitoredProjects of the relevant metrics scope
354+
log.Printf("[DEBUG] Matching ProjectNumbers: %s to %s.", expectedProjectNumber, monitoredProjectName)
355+
if strings.HasSuffix(monitoredProjectName.(string), fmt.Sprintf("/%s", expectedProjectNumber)) {
356+
// Match found - set response object name to match
357+
res["name"] = monitoredProjectName
358+
log.Printf("[DEBUG] Matched ProjectNumbers: %s and %s.", expectedProjectNumber, monitoredProjectName)
359+
return res, nil
408360
}
409-
res["name"] = project.ProjectId
410361
}
411-
return res, nil
362+
log.Printf("[DEBUG] MonitoringMonitoredProject couldn't be matched.")
363+
return nil, nil
412364
}
413365

414366
func resourceMonitoringMonitoredProjectResourceV0() *schema.Resource {

google/services/monitoring/resource_monitoring_monitored_project_sweeper.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func testSweepMonitoringMonitoredProject(region string) error {
108108
continue
109109
}
110110

111-
deleteTemplate := "https://monitoring.googleapis.com/v1/locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}}"
111+
deleteTemplate := "https://monitoring.googleapis.com/v1/{{name}}"
112112
deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate)
113113
if err != nil {
114114
log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err)

0 commit comments

Comments
 (0)