diff --git a/.changelog/12736.txt b/.changelog/12736.txt new file mode 100644 index 0000000000..350440af98 --- /dev/null +++ b/.changelog/12736.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +accesscontextmanager: added `etag` to `google_access_context_manager_service_perimeter_resource` to prevent overriding list of resources +``` \ No newline at end of file diff --git a/google-beta/services/accesscontextmanager/resource_access_context_manager_service_perimeter_resource.go b/google-beta/services/accesscontextmanager/resource_access_context_manager_service_perimeter_resource.go index ef803636c0..e69e6c5ba2 100644 --- a/google-beta/services/accesscontextmanager/resource_access_context_manager_service_perimeter_resource.go +++ b/google-beta/services/accesscontextmanager/resource_access_context_manager_service_perimeter_resource.go @@ -67,6 +67,11 @@ Format: projects/{project_number}`, Computed: true, Description: `The name of the Access Policy this resource belongs to.`, }, + "etag": { + Type: schema.TypeString, + Computed: true, + Description: `The perimeter etag is internally used to prevent overwriting the list of perimeter resources on PATCH calls. It is retrieved from the same GET perimeter API call that's used to get the current list of resources. The resource to add or remove is merged into that list and then this etag is sent with the PATCH call along with the updated resource list.`, + }, }, UseJSONNumber: true, } @@ -122,6 +127,21 @@ func resourceAccessContextManagerServicePerimeterResourceCreate(d *schema.Resour } headers := make(http.Header) + etag := d.Get("etag").(string) + + if etag == "" { + log.Printf("[ERROR] Unable to get etag: %s", err) + return nil + } + obj["etag"] = etag + + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + updateMask := []string{"status.resources", "etag"} + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ Config: config, Method: "PATCH", @@ -213,10 +233,9 @@ func resourceAccessContextManagerServicePerimeterResourceRead(d *schema.Resource if err != nil { return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("AccessContextManagerServicePerimeterResource %q", d.Id())) } - // post_read template for access_context_manager_service_perimeter_resource - - // this is a placeholder for now but in the future we can use this to access - // the etag from the read response + if err := d.Set("etag", res["etag"]); err != nil { + log.Printf("[ERROR] Unable to set etag: %s", err) + } res, err = flattenNestedAccessContextManagerServicePerimeterResource(d, meta, res) if err != nil { @@ -233,6 +252,9 @@ func resourceAccessContextManagerServicePerimeterResourceRead(d *schema.Resource if err := d.Set("resource", flattenNestedAccessContextManagerServicePerimeterResourceResource(res["resource"], d, config)); err != nil { return fmt.Errorf("Error reading ServicePerimeterResource: %s", err) } + if err := d.Set("etag", flattenNestedAccessContextManagerServicePerimeterResourceEtag(res["etag"], d, config)); err != nil { + return fmt.Errorf("Error reading ServicePerimeterResource: %s", err) + } return nil } @@ -275,6 +297,21 @@ func resourceAccessContextManagerServicePerimeterResourceDelete(d *schema.Resour } headers := make(http.Header) + etag := d.Get("etag").(string) + + if etag == "" { + log.Printf("[ERROR] Unable to get etag: %s", err) + return nil + } + obj["etag"] = etag + + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + updateMask := []string{"status.resources", "etag"} + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } log.Printf("[DEBUG] Deleting ServicePerimeterResource %q", d.Id()) res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ @@ -328,6 +365,10 @@ func flattenNestedAccessContextManagerServicePerimeterResourceResource(v interfa return v } +func flattenNestedAccessContextManagerServicePerimeterResourceEtag(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandNestedAccessContextManagerServicePerimeterResourceResource(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -486,10 +527,9 @@ func resourceAccessContextManagerServicePerimeterResourceListForPatch(d *schema. if err != nil { return nil, err } - // post_read template for access_context_manager_service_perimeter_resource - - // this is a placeholder for now but in the future we can use this to access - // the etag from the read response + if err := d.Set("etag", res["etag"]); err != nil { + log.Printf("[ERROR] Unable to set etag: %s", err) + } var v interface{} var ok bool if v, ok = res["status"]; ok && v != nil { diff --git a/website/docs/r/access_context_manager_service_perimeter_resource.html.markdown b/website/docs/r/access_context_manager_service_perimeter_resource.html.markdown index 3dc3316201..3b172a8fb5 100644 --- a/website/docs/r/access_context_manager_service_perimeter_resource.html.markdown +++ b/website/docs/r/access_context_manager_service_perimeter_resource.html.markdown @@ -99,6 +99,9 @@ In addition to the arguments listed above, the following computed attributes are * `access_policy_id` - The name of the Access Policy this resource belongs to. +* `etag` - + The perimeter etag is internally used to prevent overwriting the list of perimeter resources on PATCH calls. It is retrieved from the same GET perimeter API call that's used to get the current list of resources. The resource to add or remove is merged into that list and then this etag is sent with the PATCH call along with the updated resource list. + ## Timeouts