See the supported connectors for Application Integration.

Cloud Function task

The Cloud Function task lets you configure and run Google Cloud Functions from your integration. Google Cloud Functions is a lightweight compute solution for developers to create single-purpose, stand-alone functions that respond to Cloud events without the need to manage a server or a runtime environment.

For more information, see Google Cloud Functions documentation.

Before you begin

Ensure that you perform the following tasks in your Google Cloud project before configuring the Cloud Function task.

  1. Enable the Cloud Functions API (cloudfunctions.googleapis.com).

    Enable Cloud Functions API

  2. Assign the following IAM roles to your principal:
    • Cloud Functions Admin
    • Application Integration Editor

    For information on granting roles to principals, see Granting, changing, and revoking access.

  3. To connect to Cloud Functions, ensure that you have either created an OAuth 2.0 profile or attached a user-managed service account to your integration:
    • If your integration has a service account attached, assign the Cloud Function Invoker IAM role to that service account.

      For information about granting roles to a service account, see Manage access to service accounts.

    • The Cloud Function task only supports authentication profiles of type Google OIDC ID Token. Create an authentication profile of type Google OIDC ID Token using the service account with the Cloud Function Invoker IAM role assigned. If your Cloud Function task does not require authentication, the Authentication profile field in the task configuration pane can be left empty.

    If your integration has both OIDC ID profile and a user-managed service account configured, then by default the OIDC ID profile is used for authentication. If neither OIDC ID profile nor user-managed service account is configured, then the default service account (service-PROJECT_NUMBER@gcp-sa-integrations.iam.gserviceaccount.com) is used to call the Cloud Function task.

  4. Ensure that VPC Service Controls is NOT setup for Application Integration in your Google Cloud project.

Configure the Cloud Function task

To configure the Cloud Function task in your integration, perform the following steps:

  1. In the Google Cloud console, go to the Application Integration page.

    Go to Application Integration

  2. In the navigation menu, click Integrations.

    The Integrations page appears listing all the integrations available in the Google Cloud project.

  3. Select an existing integration or click Create integration to create a new one.

    If you are creating a new integration:

    1. Enter a name and description in the Create Integration pane.
    2. Select a region for the integration.
    3. Select a service account for the integration. You can change or update the service account details of an integration any time from the Integration summary pane in the integration toolbar.
    4. Click Create.

    This opens the integration in the integration editor.

  4. In the integration editor navigation bar, click Tasks to view the list of available tasks.
  5. Click and place the Cloud Function element to the integration editor.
  6. Click the Cloud Function element on the designer to open the configuration pane, then click Configure Cloud Function.
  7. In the Cloud Function Configuration dialog, choose any one of the following:
    • Link existing function. Select this option to link an existing Cloud Function that is configured in integration. Enter the Cloud Function Trigger URL.
    • Create new function. Select this option to create a new Cloud Function associated with integration. Enter the Cloud Function Name and select the function region from the drop-down list.
  8. Click Save.

    A basic Google Cloud function is created in your Google Cloud project and is associated with your integration. The task configuration pane displays the Trigger URL and the Task Parameters of the Cloud Function.

Cloud function template

When configuring the Cloud Function using an existing Cloud function, make sure that the function's main.py, task.py, and requirements.txt source files are in the following format:

task.py

  # Sample Code:
  # print(event.get('task_string_key'))
  # event.set('task_int_array_key', [456, 789]);
  # event.log('some logging')
  
  def run(event):
    """Actual cloud function custom logic.
    Args:
      event : event object in main.py that contains all parameters.
    """
    return     

main.py

  """Un-editable platform wrapper which invokes user code."""
import traceback

from flask import json
from flask import jsonify
from task import run

VALUE_NAME = [
    'stringValue', 'intValue', 'doubleValue', 'booleanValue', 'protoValue'
]
ARRAY_VALUE_NAME = {
    'stringArray': 'stringValues',
    'intArray': 'intValues',
    'doubleArray': 'doubleValues',
    'booleanArray': 'booleanValues',
    'protoArray': 'protoValues'
}
VALUE_TYPE_URL = 'type.googleapis.com/google.protobuf.Value'
CLOUD_FUNCTION_EXCEPTION_KEY = 'CloudFunctionException'
CLOUD_FUNCTION_LOGGING_KEY = 'CloudFunctionLogging'


class _Event(object):
  """Event object."""

  def __init__(self, json_payload):
    self._event_params = json_payload.get('eventParameters', dict())
    self._task_params = json_payload.get('taskParameters', dict())
    self._log = []
    print('Event param is ' + str(self._event_params))
    print('Task param is ' + str(self._task_params))

  def set(self, key, value):
    """Set the event parameters key-value.

    Args:
      key: parameter key.
      value: parameter value.
    """
    new_param = self._create_param(key, value)
    param = self._get_param_by_key(key)
    if param is None:
      if 'parameters' not in self._event_params:
        self._event_params['parameters'] = []
      self._event_params['parameters'].append(new_param)
    else:
      param['value'] = new_param['value']

  def _create_param(self, key, value):
    """Create a new parameter with given key value pair.

    Args:
      key: parameter key.
      value: parameter value.

    Returns:
      parameter.
    """
    new_param = {}
    new_param['key'] = key
    if isinstance(value, str):
      new_param['value'] = {'stringValue': value}
    elif isinstance(value, int):
      new_param['value'] = {'intValue': value}
    elif isinstance(value, float):
      new_param['value'] = {'doubleValue': value}
    elif isinstance(value, bool):
      new_param['value'] = {'booleanValue': value}
    elif isinstance(value, dict):
      if 'type@' in value:
        new_param['value'] = {'protoValue': value}
      else:
        new_param['value'] = {
            'protoValue': {
                '@type': 'type.googleapis.com/google.protobuf.Value',
                'value': value
            }
        }
    elif isinstance(value, list):
      if not value:
        raise RuntimeError('Cannot create a param with empty list')
      if any(not isinstance(val, type(value[0])) for val in value):
        print('Not all elements in the list have the same type')
        new_param['value'] = {
            'protoValue': {
                '@type': 'type.googleapis.com/google.protobuf.Value',
                'value': value
            }
        }
      elif isinstance(value[0], str):
        new_param['value'] = {'stringArray': {'stringValues': value}}
      elif isinstance(value[0], int):
        new_param['value'] = {'intArray': {'intValues': value}}
      elif isinstance(value[0], float):
        new_param['value'] = {'doubleArray': {'doubleValues': value}}
      elif isinstance(value[0], bool):
        new_param['value'] = {'booleanArray': {'booleanValues': value}}
      elif isinstance(value[0], dict):
        if all('@type' in val and val['@type'] == value[0]['@type']
               for val in value):
          new_param['value'] = {'protoArray': {'protoValues': value}}
        else:
          new_param['value'] = {
              'protoValue': {
                  '@type': 'type.googleapis.com/google.protobuf.Value',
                  'value': value
              }
          }
      else:
        raise RuntimeError('The type ' + type(value[0]) +
                           ' in the list is not supported')
    else:
      raise RuntimeError('Value ' + str(value) + ' has the type ' +
                         type(value) + ' that is not supported')
    return new_param

  def get(self, key):
    """Get the event parameter value for specified key.

    Args:
      key: parameter key.

    Returns:
      Parameter value.
    """
    param = self._get_param_by_key(key)
    if param is None:
      raise RuntimeError('Can not find param with key ' + key)
    return self._get_param_value(param)

  def _get_param_by_key(self, key):
    """Get the parameter for specified key.

    Args:
      key: parameter key.

    Returns:
      Parameter.
    """
    param = self._get_param_by_key_from_params(key, self._task_params)
    if param is None:
      return self._get_param_by_key_from_params(key, self._event_params)
    value = self._get_param_value(param)
    if isinstance(value, str) and len(value) > 2 and value.startswith(
        '$') and value.endswith('$'):
      return self._get_param_by_key_from_params(value[1:-1], self._event_params)
    return param

  def _get_param_by_key_from_params(self, key, params):
    """Get the parameter for specified key from event parameters.

    Args:
      key: parameter key.
      params: event parameters.

    Returns:
      Parameter.
    """
    if not isinstance(params, dict) or 'parameters' not in params:
      return None
    for param in params['parameters']:
      if param['key'] == key:
        return param
    return None

  def _get_param_value(self, param):
    """Get the parameter value for specified parameter.

    Args:
      param: parameter.

    Returns:
      Parameter value.
    """
    value = param['value']
    if len(value) != 1:
      raise RuntimeError('param does not have size of 1')
    for value_name in VALUE_NAME:
      if value_name in value:
        if value_name == 'protoValue' and value[value_name][
            '@type'] == VALUE_TYPE_URL:
          return value[value_name]['value']
        return value[value_name]
    for array_value_name in ARRAY_VALUE_NAME:
      if array_value_name in value:
        return value[array_value_name][ARRAY_VALUE_NAME[array_value_name]]
    raise RuntimeError('Cannot get value from param ' + str(param))

  def set_error(self):
    """Set the cloud function error to event parameters in order for user to see on IP."""

    self.set(CLOUD_FUNCTION_EXCEPTION_KEY, traceback.format_exc())

  def log(self, message):
    self._log.append(str(message))

  def get_response(self):
    """Get the response that can be returned to IP.

    Returns:
      The response text or any set of values that can be turned into a
      Response object using
      `make_response
      <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
    """
    if self._log:
      self.set(CLOUD_FUNCTION_LOGGING_KEY, self._log)
    res = {
        'eventParameters': self._event_params,
    }
    return jsonify(**json.loads(json.htmlsafe_dumps(res)))


def execute_function(request):
  """Entry point of the cloud function.

  Args:
    request (flask.Request): HTTP request object.

  Returns:
    The response text or any set of values that can be turned into a
    Response object using
    `make_response
    <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
  """
  try:
    request_json = request.get_json(silent=True)
    event = _Event(request_json)
    run(event)
  except:
    event.set_error()
  return event.get_response()

requirements.txt

# Function dependencies, for example:
# package>=version

Edit a Cloud Function task

Configuring a Cloud Function task in Application Integration creates a basic HTTP triggered Cloud Function in your Google Cloud project.

To edit a Cloud Function task, perform the following steps:

  1. In the task configuration pane, click Open Cloud Function.

    You are redirected to the Function details page in your Google Cloud Console.

  2. Click Edit.
  3. The Configuration page lets you edit the default configuration settings of the Cloud Function. See Configuring Cloud Functions for more information.
  4. Click Next to edit the source code files of the Cloud Function.

    By default, the Cloud Function contains the following source files:

    • main.py : This file contains the initialization code to run the Cloud Function from your integration.
    • task.py : This file contains the executable code of the Cloud Function. Write your script inside the run(event) function. This function is called when the Cloud Function task executes. The event object from the main.py file contains all the task parameters.

      See Access integration variables for information about how to use the variables defined at the integration level in your script.

  5. Click Deploy.

Access integration variables

To access an integration variable in your Cloud Function, you must pass the variable in the form of task parameters to the Cloud Function task. The task parameters are key-value pairs where Key is the name of the reference variable used in your Cloud Function source file and the Value is the corresponding integration variable name that the reference variable points to. You can add one or more task parameters in the Task Parameters section of the task configuration pane.

The following methods are used to access integration variables from your Cloud Function:

  • set: Writes the value to a variable.
  • get: Reads the value of a variable.

For example, if you have an integration variable named EmployeeName that you want to use in your Cloud Function source file, define the following task parameters:

  • Key: EmployeeKey
  • Value: EmployeeName

The following sample script shows the usage of set and get functions to access the defined integration variables.

def run(event):
  # Read the integration variable EmployeeName using the reference variable EmployeeKey
  value = event.get('EmployeeKey');
  # Change the integration variable EmployeeName value using the reference variable EmployeeKey
  newValue = event.set('EmployeeKey' , 'XYZ');
  # The new value of the integration variable is retained throughout the Cloud Function task.
  return

Error handling strategy

An error handling strategy for a task specifies the action to take if the task fails due to a temporary error. For information about how to use an error handling strategy, and to know about the different types of error handling strategies, see Error handling strategies.

SLA exclusions

The Cloud Function task has a dependency on the Google Cloud Functions product. Because this dependency is external to the Application Integration, all executions of active integrations that fail because of the failure in the Cloud Function task, are excluded from the Application Integration Service Level Agreement (SLA) terms and conditions.