Tarea de Cloud Function

La tarea de Cloud Functions te permite configurar y ejecutar funciones de Google Cloud desde tu integración. Google Cloud Functions es una solución de procesamiento ligera para que los desarrolladores creen funciones individuales y de un solo propósito que respondan a eventos de Cloud sin necesidad de administrar un servidor o un entorno de ejecución.

Para obtener más información, consulta la documentación de Google Cloud Functions.

Antes de comenzar

Asegúrate de realizar las siguientes tareas en tu proyecto de Google Cloud antes de configurar la tarea de Cloud Functions.

  1. Habilita la API de Cloud Functions (cloudfunctions.googleapis.com).

    Habilitar la API de Cloud Functions

  2. Asigna los siguientes roles de IAM a tu principal:
    • Administrador de Cloud Functions (roles/cloudfunctions.admin)
    • Editor de Application Integration (roles/integrations.integrationEditor)
    • Usuario de la cuenta de servicio (roles/iam.serviceAccountUser)

    Para obtener información sobre cómo otorgar roles a las principales, consulta Otorga, cambia y revoca acceso.

  3. Para conectarte a Cloud Functions, asegúrate de haber creado un perfil de OAuth 2.0 o adjuntado una cuenta de servicio administrada por el usuario a tu integración:
    • Si tu integración tiene una cuenta de servicio adjunta, asigna el rol de IAM Invocador de Cloud Functions a esa cuenta de servicio.

      Para obtener información sobre cómo otorgar roles a una cuenta de servicio, consulta Administra el acceso a las cuentas de servicio.

    • La tarea de Cloud Function solo permite perfiles de autenticación de tipo Token de ID de OIDC de Google. Crea un perfil de autenticación de tipo Token de ID de OIDC de Google a través de la cuenta de servicio con el rol de IAM de invocador de Cloud Functions asignado. Si tu tarea de Cloud Functions no requiere autenticación, el campo Perfil de autenticación en el panel de configuración de las tareas se puede dejar en blanco.

    Si tu integración tiene configurados un perfil de ID de OIDC y una cuenta de servicio administrada por el usuario, el perfil de ID de OIDC se usa para la autenticación de forma predeterminada. Si no se configuran el perfil de ID de OIDC ni la cuenta de servicio administrada por el usuario, la cuenta de servicio predeterminada (service-PROJECT_NUMBER@gcp-sa-apigee.iam.gserviceaccount.com) se usa para llamar a la tarea de Cloud Functions.

  4. Asegúrate de que los Controles del servicio de VPC NO estén configurados para la integración de Apigee en tu proyecto de Google Cloud.

Configura la tarea de la función de Cloud Functions

Para configurar la tarea de Cloud Functions en tu integración, realiza los siguientes pasos:

  1. En la IU de Apigee, selecciona tu organización de Apigee.
  2. Haz clic en Desarrollar > Integraciones.
  3. Elige una integración existente o crea una nueva haciendo clic en Crear integración.

    Si creas una integración nueva, haz lo siguiente:

    1. Escribe un nombre y una descripción en el diálogo Crear integración.
    2. En la lista de regiones compatibles, elige Región para la integración.
    3. Haz clic en Crear.

    Esto abrirá la integración en la página del diseñador de integración.

  4. En la barra de navegación Diseñador de integración, haz clic en +Agregar una tarea o un activador > Tareas para ver la lista de tareas disponibles.
  5. Haz clic y coloca el elemento Cloud Function en el editor de integración.
  6. Haz clic en el elemento Cloud Function en el diseñador para abrir el panel de configuración y, luego, haz clic en Configura Cloud Function.
  7. En el cuadro de diálogo Configuración de la función de Cloud Functions, elige cualquiera de las siguientes opciones:
    • Vincular función existente Selecciona esta opción para vincular una función de Cloud Functions existente que está configurada en la integración. Ingresa la URL del activador de Cloud Functions.
    • Crea una función nueva. Selecciona esta opción para crear una función de Cloud Functions nueva asociada con la integración. Ingresa el nombre de Cloud Function y selecciona la región de función en la lista desplegable.
  8. Haz clic en Guardar.

    Se crea una función básica de Google Cloud en tu proyecto de Google Cloud y se asocia a tu integración. En el panel de configuración de tareas, se muestra la URL del activador y los Parámetros de tareas de la función de Cloud Functions.

Plantilla de Cloud Functions

Cuando configures la función de Cloud Functions con una función de Cloud existente, asegúrate de que los archivos de origen main.py, task.py y requirements.txt de la función tengan el siguiente formato:

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

Edita una tarea de Cloud Function

Configurar una tarea de Cloud Functions en Apigee Integration crea una función básica de Cloud Function activada por HTTP en tu proyecto de Google Cloud.

Para editar una tarea de Cloud Function, realiza los siguientes pasos:

  1. En el panel de configuración de la tarea, haz clic en Abrir Cloud Function.

    Se te redireccionará a la página Detalles de la función en la consola de Google Cloud.

  2. Haz clic en Edit.
  3. En la página Configuración, puedes editar la configuración predeterminada de la función de Cloud Functions. Consulta Configura Cloud Functions para obtener más información.
  4. Haz clic en Siguiente para editar los archivos de código fuente de la función de Cloud Functions.

    Según la configuración predeterminada, la función de Cloud Functions contiene los siguientes archivos fuente:

    • main.py : Este archivo contiene el código de inicialización para ejecutar la función de Cloud Functions desde tu integración.
    • task.py : este archivo contiene el código ejecutable de Cloud Function. Escribe tu secuencia de comandos dentro de la función run(event). Esta función se llama cuando se ejecuta la tarea de la función de Cloud Functions. El objeto event del archivo main.py contiene todos los parámetros de la tarea.

      Consulta Variables de integración de acceso para obtener información sobre cómo usar las variables definidas a nivel de integración en tu secuencia de comandos.

  5. Haga clic en Implementar.

Accede a variables de integración

Para acceder a una variable de integración en tu función de Cloud Functions, debes pasar la variable en forma de parámetros de tarea a la tarea de Cloud Functions. Los parámetros de la tarea son pares clave-valor en los que Key es el nombre de la variable de referencia que se usa en su archivo fuente de Cloud Function y Value es el nombre de la variable de integración correspondiente a la que apunta la variable de la referencia. Puedes agregar uno o más parámetros de tarea en la sección Parámetros de valor del panel de configuración de tareas.

Los siguientes métodos se usan para acceder a las variables de integración desde tu función de Cloud Functions:

  • set: Establece el valor para una variable.
  • get: Lee el valor de una variable.

Por ejemplo, si tienes una variable de integración llamada EmployeeName que deseas usar en tu archivo de origen de Cloud Functions, define los siguientes parámetros de tareas:

  • Key: EmployeeKey
  • Value: EmployeeName

En la siguiente secuencia de comandos de ejemplo, se muestra el uso de las funciones set y get para acceder a las variables de integración definidas.

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

Estrategia de manejo de errores

Una estrategia de manejo de errores de una tarea específica la acción que se debe realizar si la tarea falla debido a un error temporal. Para obtener información sobre cómo usar una estrategia de manejo de errores y conocer los diferentes tipos de estrategias de manejo de errores, consulta Estrategias de manejo de errores.