Invalid update_mask. - how to specify a JSON update mask correctly for googleapis?

Viewed 756

I'm trying to use the following API: https://cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies.accessLevels/patch

My goal is simple: update ("patch") an "AccessLevel" object in GCP's backend.

I am calling the API using "UrlFetchApp.fetch" method from Google's Apps Script:

var result = UrlFetchApp.fetch('https://accesscontextmanager.googleapis.com/v1/accessPolicies/12345678/accessLevels/User_A_Home_IP?updateMask=updateMask',options);

where "options" (passed as the 2nd param after the url endpoint) is:

  var options = 
  {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
      'Content-Type' : 'application/json',
    },
    payload : JSON.stringify(payload),
    muteHttpExceptions : true,
    "updateMask" : "*"
   }

and "payload" is:

var payload=
  {
    "basic": {
      "combiningFunction": "OR",
      "conditions": [
      {
        "ipSubnetworks": [
          "11.12.13.14/32"
        ]
      }
      ]
    },
  "name": "accessPolicies/12345678/accessLevels/User_A_Home_IP",
  "title": "User A Home IP"
  }

The result I'm getting back is:

{
  "error": {
    "code": 400,
    "message": "Invalid update_mask. All paths must be in the AccessLevel message.",
    "status": "INVALID_ARGUMENT"
  }
}

According to the documentation (first link in this post) The request body should contain an instance of AccessLevel (this is the "payload" object in my code) Also required is an "updateMask" query parameter which indicates which fields of the backend target json object get updated.

updateMask, If I understand correctly - is of Type FieldMask: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.FieldMask

I only need to update the single IP address found in the "ipSubnetworks" array of strings, that in turn is found inside the "conditions" array of objects, which in turn is nested under the "basic" object.

What is the correct syntax for updateMask in this case?

Where should updateMask be located in my "PATCH" request?

2 Answers

Specify in the updateMask the main fields you would like to update

If you update more than one field - specify all fields comma separated (without spaces inbetween).

In your case:

"updateMask" : "basic,title"

See also:

updateMask

string (FieldMask format)

Required. Mask to control which fields get updated. Must be non-empty.

This is a comma-separated list of fully qualified names of fields. Example: "user.displayName,photo".

Sample JSON:

"name": "accessPolicies/12345678/accessLevels/User_A_Home_IP",
"updateMask": "basic,title",
"title": "User A Home IP",
"resource": {
      "basic": {
          "combiningFunction": "OR",
          "conditions": [
            {
              "ipSubnetworks": [
                "11.12.13.14/32"
              ]
            }
          ]
        }
      }

UPDATE:

A sample Apps Script function:

function patchResource() {
    var options = 
  {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
      'Content-Type' : 'application/json',
    },
    payload : JSON.stringify(payload),
    muteHttpExceptions : true
   }
    
    var payload=
  {
"name": "accessPolicies/12345678/accessLevels/User_A_Home_IP",
"updateMask": "basic,title",
"title": "User A Home IP",
"resource": {
      "basic": {
          "combiningFunction": "OR",
          "conditions": [
            {
              "ipSubnetworks": [
                "11.12.13.14/32"
              ]
            }
          ]
        }
      }
  }
    
  var result = UrlFetchApp.fetch('https://accesscontextmanager.googleapis.com/v1/accessPolicies/12345678/accessLevels/User_A_Home_IP',options);
  console.log(result.getResponseCode())
  console.log(result.getContentText())
}

If you do want to pass the updateMask as a URL parameter instead of part of the payload - make sure to URL encode the comma:

?updateMask=basic%2Ctitle

function updateAccessLevelIp(accessLevelName, ip) {
  var data = {"basic":{"conditions":[{"ipSubnetworks":[ip]}]}}
  var options =
  {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
      'Content-Type' : 'application/json',
    },
    muteHttpExceptions : true,
    'payload' : JSON.stringify(data)
   }
  var result = UrlFetchApp.fetch("https://accesscontextmanager.googleapis.com/v1/accessPolicies/xxxxxxxxxxx/accessLevels/"+accessLevelName+"?updateMask=basic",options);
  console.log(result.getResponseCode())
  console.log(result.getContentText())
  if (result.getResponseCode() == 200)
    return ("Successfully updated the \"" + accessLevelName + "\" access level with ip address: \"" +  ip + "\"");
  else 
    return ("Failed to update \"" + accessLevelName + "\"! please talk to your friendly neighborhood DevOps team!\nResponse Code was:\n"+result.getResponseCode()+"\nResponse text was:\n"+result.getContentText());
}

This is working 100%: it returns http 200 and updates the ip of the access level object as wanted.

  • There is No need for any special json field to be an "update mask"; An update mask is indeed mandatory for this API call, but only as a URL parameter (Not as a json field)
Related