Integra tu solución de SaaS a la API de Google Cloud Marketplace con Producer Portal (Python)

1. Introducción

Las soluciones de SaaS en Google Cloud Marketplace son soluciones de software que se ejecutan en tu infraestructura, sin importar la ubicación, pero que factura Google.

En este codelab, configurarás una solución de SaaS básica que se integra con Google Cloud Marketplace para hacer lo siguiente:

  • Recibir notificaciones cuando un usuario se registre en la solución de muestra
  • Aprueba a los clientes que quieran registrarse y agrégalos a tu base de datos.
  • Maneja situaciones en las que los clientes quieren cambiar o cancelar sus planes de facturación.
  • Enviar informes de uso a Google

En este codelab, te familiarizarás con las APIs de Service Control y de adquisición de Google Cloud Marketplace. Ten en cuenta que esta guía no proporciona un entorno de producto completo para las pruebas.

2. Antes de comenzar

  • Usa Producer Portal para habilitar el codelab para tu proyecto, si aún no lo hiciste.

El vínculo directo a Producer Portal es el siguiente:

https://console.cloud.google.com/producer-portal?project=YOUR_PROJECT_ID

Para habilitar el codelab, haz clic en Habilitar en el panel de Codelabs que se encuentra en el lado derecho de la pantalla.

Para instalar los módulos de Python, usa el siguiente comando:

pip install --upgrade google-api-python-client google-cloud-pubsub
git clone https://github.com/googlecodelabs/gcp-marketplace-integrated-saas.git
cd gcp-marketplace-integrated-saas

  • Establece la variable de entorno GOOGLE_CLOUD_PROJECT en el ID de este proyecto:
  • Linux:
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
  • Windows:
set GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID
  • Establece la variable de entorno GOOGLE_APPLICATION_CREDENTIALS en la ruta completa al archivo descargado:
  • Linux:
export GOOGLE_APPLICATION_CREDENTIALS="[YOUR_MACHINE]/path/service-account-key.json"
  • Windows:
set GOOGLE_APPLICATION_CREDENTIALS=[YOUR_MACHINE]/path/service-account-key.json
  • Para ver una solución de muestra en Google Cloud Marketplace, visita Producer Portal y haz clic en Codelab product en el panel de Codelabs. También puedes acceder a la solución directamente en https://console.cloud.google.com/marketplace/product/DEMO-YOUR_PROJECT_ID/isaas-codelab
  • En la consola de Google Cloud, en tu proyecto nuevo, habilita la API de Partner Procurement.

A continuación, configura el backend para la solución de ejemplo.

3. Integración con Google Cloud Marketplace

En un nivel alto, integras la solución de muestra en Google Cloud Marketplace de las siguientes maneras:

  • Integra en Cloud Pub/Sub para recibir notificaciones de Google Cloud Marketplace, como cuando un usuario se registra para la solución. Tu ingeniero socio crea un tema de Cloud Pub/Sub al que te debes suscribir para recibir notificaciones.
  • Integra la API de Partner Procurement para crear cuentas para clientes nuevos. Usas la API de Partner Procurement para actualizar las cuentas cuando los usuarios seleccionan, cambian o cancelan sus planes de suscripción. Para integrarte en la API, deberás compilar tu propia biblioteca cliente.
  • Realiza la integración con el Control de servicios de Google para informar la información de uso.

4. Suscríbete al tema de Cloud Pub/Sub

Cuando un usuario elige un plan de suscripción, recibes una notificación de Google Cloud Marketplace a través de un tema de Cloud Pub/Sub.

Para escuchar mensajes en un tema de Cloud Pub/Sub, primero debes crear una suscripción.

Para crear una suscripción, usa la secuencia de comandos create_subscription.py:

cd gcp-marketplace-integrated-saas/tools
python create_subscription.py

Para ver la suscripción, abre el panel de Cloud Pub/Sub en la consola de Cloud:

https://console.cloud.google.com/cloudpubsub/subscriptions

Prueba una solicitud de suscripción de prueba

Para probar esta app de ejemplo como usuario, visita https://console.cloud.google.com/marketplace/product/DEMO-YOUR_PROJECT_ID/isaas-codelab y abre el producto del codelab en Marketplace. Asegúrate de tener seleccionado tu proyecto del codelab y elige un plan de suscripción.

Para ver los mensajes de Cloud Pub/Sub que se envían cuando eliges un plan, navega a la raíz del directorio python3 en el repositorio y ejecuta el siguiente comando:

~/gcp-marketplace-integrated-saas/python3$ python -m impl.step_1_pubsub.app

Para ver el código de muestra que detecta mensajes de Cloud Pub/Sub, consulta https://github.com/googlecodelabs/gcp-marketplace-integrated-saas/blob/master/python3/impl/step_1_pubsub/app.py.

En el mensaje de Cloud Pub/Sub, el campo eventType muestra por qué se envió el mensaje. Cuando elijas un plan, deberías ver un mensaje para eventType: ENTITLEMENT_CREATION_REQUESTED, que representa tu elección anterior del plan de suscripción.

Si cancelas tu plan mientras se ejecuta este script, verás un nuevo mensaje para eventType: ENTITLEMENT_CANCELLED.

Ten en cuenta que la muestra anterior no confirma la recepción de los mensajes. Esto te permite realizar pruebas con mayor facilidad, ya que recibirás los mismos mensajes cada vez que ejecutes la app.

Para cerrar el script, presiona CTRL + \.

5. Aprobar la solicitud de la cuenta

Ahora que puedes recibir mensajes de Google Cloud Marketplace, debes comenzar a controlar los recursos que el servicio de aprovisionamiento de Google Cloud Marketplace crea en nombre del cliente.

El primero es el recurso account. Una cuenta representa la conexión de un cliente con tu producto. Debes almacenar el ID de la cuenta de Adquisiciones del cliente en tu base de datos para asignar la relación entre su Cuenta de Google y su cuenta de tu servicio.

Cuando un cliente elige un plan, Google Cloud Marketplace envía una notificación de Cloud Pub/Sub que indica que el cliente solicita una cuenta. Tu app debe aprobar la solicitud. En este codelab, aprobarás las solicitudes de cuentas cuando se reciban los mensajes de Cloud Pub/Sub.

Crea la base de datos para la información de la cuenta

En este codelab, usaremos una base de datos JSON simple que puede hacer un seguimiento de las cuentas y las compras de los clientes.

Para probar este ejemplo, crea un archivo con un objeto JSON vacío en cualquier lugar de tu estación de trabajo:

{}

Establece la variable de entorno PROCUREMENT_CODELAB_DATABASE en la ruta completa a este archivo:

  • Linux:
export PROCUREMENT_CODELAB_DATABASE="YOUR_MACHINE/path/EMPTY_JSON_OBJECT.json"
  • Windows:
set PROCUREMENT_CODELAB_DATABASE=YOUR_MACHINE/path/EMPTY_JSON_OBJECT.json

El módulo que lee y escribe en la base de datos se encuentra en python3/impl/database.

La implementación de muestra usa un esquema que se puede extender si integras más de una oferta de productos con Google Cloud Marketplace. A continuación, se muestra un ejemplo de entrada de base de datos para un usuario que se suscribió al plan Very Good en la app de ejemplo:

{
   "a2b3c4d5-b3f1-4dea-b134-generated_id":{
      "procurement_account_id":"generated-b3f1-4dea-b134-4a1d100c0335",
      "internal_account_id":"generated-45b7-4f4d-1bcd-2abb114f77de",
      "products":{
         "isaas-codelab":{
            "start_time":"2019-01-04T01:21:16.188Z",
            "plan_id":"very-good",
            "product_id":"isaas-codelab",
            "consumer_id":"project_number:123123345345"
         }
      }
   }
}

En la implementación final, debes conectar tu app con tus propias bases de datos para vincular las cuentas de Google Cloud Marketplace de los clientes con tus propios recursos de clientes.

Aprobar la cuenta

Para aprobar la solicitud de la cuenta, ejecuta el siguiente comando:

~/gcp-marketplace-integrated-saas/python3$ python3 -m impl.step_2_account.app

El código de muestra para aprobar una cuenta se encuentra en impl/step_2_account.

La implementación de muestra usa la clase Procurement, que controla las interacciones con la API de Procurement. Estos son sus métodos get_account() y approve_account():

step_2_account/app.py

def _get_account_name(self, account_id):
    return 'providers/DEMO-{}/accounts/{}'.format(PROJECT_ID,
                                                  account_id)

def get_account(self, account_id):
    """Gets an account from the Procurement Service."""
    name = self._get_account_name(account_id)
    request = self.service.providers().accounts().get(name=name)
    try:
        response = request.execute()
        return response
    except HttpError as err:
        if err.resp.status == 404:
            return None

def approve_account(self, account_id):
    """Approves the account in the Procurement Service."""
    name = self._get_account_name(account_id)
    request = self.service.providers().accounts().approve(
        name=name, body={'approvalName': 'signup'})
    request.execute()

En este codelab, en el servicio de Procurement, el ID del proveedor es DEMO-YOUR_PROJECT_ID, donde YOUR_PROJECT_ID es el proyecto que creaste. Cuando interactúes con la API de Procurement, el nombre de la cuenta debe usar el siguiente formato:

providers/DEMO-YOUR_PROJECT_ID/accounts/account-id

A continuación, aprobarás un derecho, que es un registro de la compra del cliente.

6. Aprobar el derecho

Cuando un cliente elige un plan de suscripción en Google Cloud Marketplace, se crea una cuenta y, luego, se crea de inmediato una nueva solicitud de autorización. El derecho representa la compra de un servicio. Antes de que el cliente pueda comenzar a usar el servicio, debes aprobar la solicitud de derechos y, luego, configurar el servicio para que el cliente pueda comenzar a usarlo.

Cuando la app de ejemplo recibe un mensaje de Cloud Pub/Sub con eventType ENTITLEMENT_CREATION_REQUESTED, se aprueba el derecho y la app debe esperar un mensaje ENTITLEMENT_ACTIVE para registrar el derecho en la base de datos y, luego, configurar los recursos para el cliente.

Para crear el derecho, ejecuta el siguiente comando:

~/gcp-marketplace-integrated-saas/python3$ python3 -m impl.step_3_entitlement_create.app

El código para aprobar el derecho se encuentra en la implementación de muestra.

A continuación, abordarás situaciones en las que un cliente solicita un cambio en su plan de suscripción.

7. Cómo aprobar cambios en un derecho

Si tu servicio tiene varios planes, debes controlar las solicitudes de los clientes que deseen actualizar o cambiar a una versión inferior su plan existente.

Si tu servicio solo tiene un plan, ve a Controla las compras canceladas.

No hay diferencias técnicas entre que un derecho se active por primera vez y que se active después de un cambio de plan. Por este motivo, la implementación de muestra tiene un método handleActiveEntitlement() compartido para ambos casos. Este método verifica los mensajes entrantes en busca de eventos relacionados con derechos:

step_4_entitlement_change/app.py

def handleActiveEntitlement(self, entitlement, customer, accountId):
  """Updates the database to match the active entitlement."""

  product = {
      'product_id': entitlement['product'],
      'plan_id': entitlement['plan'],
  }

  if 'consumerId' in entitlement:
    product['consumer_id'] = entitlement['consumerId']

  customer['products'][entitlement['product']] = product

  self.db.write(accountId, customer)

En el siguiente fragmento, se verifica si eventType es ENTITLEMENT_PLAN_CHANGE_REQUESTED o ENTITLEMENT_PLAN_CHANGED:

step_4_entitlement_change/app.py

elif eventType == 'ENTITLEMENT_PLAN_CHANGE_REQUESTED':
  if state == 'ENTITLEMENT_PENDING_PLAN_CHANGE_APPROVAL':
    # Don't write anything to our database until the entitlement becomes
    # active within the Procurement Service.
    self.approveEntitlementPlanChange(id, entitlement['newPendingPlan'])
    return True

elif eventType == 'ENTITLEMENT_PLAN_CHANGED':
  if state == 'ENTITLEMENT_ACTIVE':
    # Handle an active entitlement after a plan change.
    self.handleActiveEntitlement(entitlement, customer, accountId)
    return True

En tu implementación final, cuando el derecho vuelva al estado ENTITLEMENT_ACTIVE, tu método de escucha deberá actualizar la base de datos para reflejar el cambio y realizar el aprovisionamiento necesario.

Según cómo configures tu producto con el ingeniero socio, es posible que tu servicio no permita cambios a una versión inferior ni cancelaciones hasta el final de un ciclo de facturación. En esos casos, el cambio de plan seguirá pendiente incluso después de la aprobación, pero el derecho no volverá al estado ENTITLEMENT_ACTIVE hasta que se complete el cambio de plan.

Para ver el código que verifica y aprueba los cambios en los derechos, consulta la implementación de ejemplo.

A continuación, debes abordar las situaciones en las que los clientes cancelan sus compras.

8. Cómo controlar las compras canceladas

Los clientes pueden cancelar sus compras. Según cómo configures el producto con tu ingeniero socio, la cancelación puede entrar en vigencia de inmediato o al final del ciclo de facturación.

Cuando un cliente cancela su compra, se envía un mensaje con el eventType ENTITLEMENT_PENDING_CANCELLATION. Si configuraste tu producto para que procese las cancelaciones de inmediato, se enviará un mensaje con eventType ENTITLEMENT_CANCELLED poco después.

step_5_entitlement_cancel/app.py

elif eventType == 'ENTITLEMENT_CANCELLED':
  # Clear out our records of the customer's plan.
  if entitlement['product'] in customer['products']:
    del customer['products'][entitlement['product']]

  ### TODO: Turn off customer's service. ###
  self.db.write(accountId, customer)
  return True

elif eventType == 'ENTITLEMENT_PENDING_CANCELLATION':
  # Do nothing. We want to cancel once it's truly canceled. For now it's
  # just set to not renew at the end of the billing cycle.
  return True

elif eventType == 'ENTITLEMENT_CANCELLATION_REVERTED':
  # Do nothing. The service was already active, but now it's set to renew
  # automatically at the end of the billing cycle.
  return True

Tu servicio debe esperar el mensaje ENTITLEMENT_CANCELLED para quitar el derecho de tu base de datos y desactivar el servicio para el cliente.

Después de que se cancela el derecho, se borra de los sistemas de Google y se envía un mensaje con eventType ENTITLEMENT_DELETED:

step_5_entitlement_cancel/app.py

elif eventType == 'ENTITLEMENT_DELETED':
  # Do nothing. Entitlements can only be deleted when they are already
  # cancelled, so our state is already up-to-date.
  return True

Para ver el código que cancela el derecho, consulta la implementación de muestra.

9. Envío de informes de uso

Algunos servicios tienen componentes basados en el uso, en los que Google necesita conocer el uso que hacen los clientes del servicio para cobrarles el importe correcto. Tu servicio debe informar el uso a través de la API de Google Service Control.

Si tu servicio no tiene componentes basados en el uso, omite esta sección.

Para obtener información detallada sobre el envío de informes de uso, consulta la documentación de incorporación.

Los informes de uso se deben enviar a la API de Control de servicios de Google cada hora. En este codelab, los informes se envían con una secuencia de comandos que podrías programar como un trabajo cron. La secuencia de comandos almacena la hora del último informe de uso en la base de datos y la usa como hora de inicio para medir el uso.

La secuencia de comandos verifica cada cliente activo del servicio y envía un informe de uso al Control de servicios de Google con el campo consumer_id del derecho del cliente. Luego, la secuencia de comandos actualiza la entrada de la base de datos del cliente para que tenga un last_report_time establecido en la hora de finalización del informe de uso que se acaba de enviar.

Google Service Control expone dos métodos: check y report. El primero siempre debe llamarse inmediatamente antes de una llamada al segundo. Si el primero tiene algún error, se debe inhabilitar el servicio del cliente hasta que se solucione.

Todo el uso de un derecho determinado se atribuye a un solo usageReportingId. Sin embargo, en el caso de los productos de SaaS, este uso se asocia con el concepto [Charges not specific to a project] en la facturación de Google Cloud. Si es posible que tu producto de SaaS se comparta ampliamente dentro de la organización de un cliente y deseas admitir la atribución de costos, te recomendamos que todos tus servicios incluyan el campo opcional userLabels en su operación de informe de uso.

Google Cloud Marketplace reserva las claves de etiquetas cloudmarketplace.googleapis.com/resource_name y cloudmarketplace.googleapis.com/container_name. Estas etiquetas tienen como objetivo capturar el contexto del uso dentro de la jerarquía de recursos y servicios nativos. Los nombres asignados por el cliente a estos recursos se incluirían como valores de etiquetas en los informes de uso. Te recomendamos que incluyas estas etiquetas en tus informes de uso de forma predeterminada.

Clave de etiqueta

Valor de etiqueta

Descripción

cloudmarketplace.googleapis.com/resource_name

RESOURCE_NAME

Es el nombre del recurso asociado a una métrica de uso.

cloudmarketplace.googleapis.com/container_name

CONTAINER_NAME

Es el nombre de un contenedor de recursos.

En el siguiente fragmento, se informa el uso de la app de demostración y se atribuye el uso del producto de SaaS al recurso asignado por el cliente llamado products_db. En este codelab, el service_name es isaas-codelab.mp-marketplace-partner-demos.appspot.com.

operation = {
  'operationId': '<UUID>',
  'operationName': 'Codelab Usage Report',
  'consumerId': 'project_number:<Project Number>',
  'startTime': '<Timestamp>',
  'endTime': '<Timestamp>',
  'metricValues': [{
      'int64Value': 100,
  }],
  'userLabels': {
    'cloudmarketplace.googleapis.com/container_name': 'saas-storage-solutions',
    'cloudmarketplace.googleapis.com/resource_name': 'products_db'
  }
}

service.services().report(
    serviceName=service_name, body={
        'operations': [operation]
    }).execute()
product['last_report_time'] = end_time
database.write(customer_id, customer)

Consulta la implementación de muestra de esta secuencia de comandos para ver el código completo. Para generar un informe de uso de muestra, ejecuta el siguiente comando:

~/gcp-marketplace-integrated-saas/python3$ python3 -m impl.step_6_usage_reporting.report isaas-codelab.mp-marketplace-partner-demos.appspot.com

10. ¡Felicitaciones!

Aprendiste cómo tu solución de SaaS puede integrarse en Google Cloud Marketplace para controlar las cuentas y los derechos de los clientes, y para informar el uso en relación con un servicio. Para ver los pasos de integración completos, consulta la documentación de la integración del backend.

Haz una limpieza

Si ya no planeas usarlos, borra los siguientes recursos:

  • La suscripción a Cloud Pub/Sub
  • La cuenta de servicio y sus claves
  • De manera opcional, el proyecto que creaste
  • Opcionalmente, la cuenta de facturación que creaste

¿Qué sigue?

Integra tu frontend

En los ejemplos de este codelab, se aprueban automáticamente las cuentas y los derechos. En la práctica, se debe dirigir a tus clientes a una página de registro que crees, en la que puedan crear cuentas en tu sistema. Después de que se registren correctamente, debes realizar las solicitudes a la API para aprobar sus cuentas y derechos.

Para obtener información sobre la integración del frontend de tu app, consulta la documentación de Google Cloud Marketplace.

Más información para ofrecer soluciones de SaaS

Para obtener una descripción general de la oferta de soluciones de SaaS en Google Cloud Marketplace, consulta Oferta de soluciones de SaaS.