使用 Producer Portal 将您的 SaaS 解决方案与 Google Cloud Marketplace API 集成 (Python)

1. 简介

Google Cloud Marketplace 上的 SaaS 解决方案是可在您的基础架构上运行的软件解决方案,无论位于何处,都由 Google 收费。

在此 Codelab 中,您将设置一个与 Google Cloud Marketplace 集成的基本 SaaS 解决方案,以实现以下目的:

  • 当用户注册使用示例解决方案时,接收通知。
  • 批准想要注册的客户,并将他们添加到您的数据库中。
  • 处理客户想要更改或取消结算方案的情况。
  • 向 Google 发送使用情况报告。

此 Codelab 可帮助您熟悉 Google Cloud Marketplace 购买与 Service Control API。请注意,本指南并未提供完整的测试产品环境。

2. 准备工作

  • 使用 Producer Portal 为您的项目启用 Codelab(如果您尚未启用)。

Producer Portal 的直接链接是:

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

如需启用 Codelab,请点击屏幕右侧“Codelab”面板中的启用

如需安装 Python 模块,请使用以下命令:

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

  • GOOGLE_CLOUD_PROJECT 环境变量设置为此项目的 ID:
  • Linux:
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
  • Windows:
set GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID
  • GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为下载文件的完整路径:
  • Linux:
export GOOGLE_APPLICATION_CREDENTIALS="[YOUR_MACHINE]/path/service-account-key.json"
  • Windows:
set GOOGLE_APPLICATION_CREDENTIALS=[YOUR_MACHINE]/path/service-account-key.json
  • 如需在 Google Cloud Marketplace 中查看示例解决方案,请访问 Producer Portal,然后点击 Codelabs 面板中的 Codelab 产品。您还可以直接访问该解决方案,网址为 https://console.cloud.google.com/marketplace/product/DEMO-YOUR_PROJECT_ID/isaas-codelab
  • 在 Google Cloud 控制台中,在新项目中启用 Partner Procurement API

接下来,为示例解决方案设置后端。

3. 与 Google Cloud Marketplace 集成

概括来讲,您可以通过以下方式将示例解决方案与 Google Cloud Marketplace 集成:

  • 与 Cloud Pub/Sub 集成,以接收来自 Google Cloud Marketplace 的通知,例如当用户注册您的解决方案时。合作伙伴工程师会为您创建一个 Cloud Pub/Sub 主题,您必须订阅此主题才能收到通知。
  • 与 Partner Procurement API 集成以便为新客户创建账号。当用户选择、更改或取消订阅方案时,您可以使用 Partner Procurement API 更新账号。若要与该 API 集成,您需要构建自己的客户端库。
  • 与 Google Service Control 集成以报告使用情况信息。

4. 订阅 Cloud Pub/Sub 主题

当用户选择订阅方案时,您会通过 Cloud Pub/Sub 主题收到来自 Google Cloud Marketplace 的通知。

如需监听 Cloud Pub/Sub 主题上的消息,您必须先创建订阅。

如需创建订阅,请使用 create_subscription.py 脚本:

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

如需查看订阅,请在 Cloud Console 中打开 Cloud Pub/Sub 信息中心:

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

尝试测试订阅请求

如需以用户身份测试此示例应用,请访问 https://console.cloud.google.com/marketplace/product/DEMO-YOUR_PROJECT_ID/isaas-codelab,在 Marketplace 中打开相应 Codelab 产品。确保您已选择 Codelab 项目,然后选择订阅方案。

如需查看选择方案时发送的 Cloud Pub/Sub 消息,请前往代码库中 python3 目录的根目录,然后运行以下命令:

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

如需查看用于监听 Cloud Pub/Sub 消息的示例代码,请参阅 https://github.com/googlecodelabs/gcp-marketplace-integrated-saas/blob/master/python3/impl/step_1_pubsub/app.py

在 Cloud Pub/Sub 消息中,eventType 字段显示了发送消息的原因。选择方案后,您应该会看到一条消息,其中包含 eventType: ENTITLEMENT_CREATION_REQUESTED,表示您之前选择的订阅方案。

如果您在脚本运行期间取消方案,系统会显示一条新消息,即 eventType: ENTITLEMENT_CANCELLED

请注意,上述示例不会确认消息。这样一来,您就可以更轻松地进行测试,因为每次运行应用时都会收到相同的消息。

如需关闭脚本,请按 CTRL + \

5. 批准账号申请

现在,您可以接收来自 Google Cloud Marketplace 的消息,接下来必须开始处理 Google Cloud Marketplace 购买服务代表客户创建的资源。

第一个是账号资源。账号表示客户与您的产品的关联。您必须在数据库中存储客户的采购账号 ID,以便将客户的 Google 账号与客户在您服务中的账号相关联。

当客户选择方案时,Google Cloud Marketplace 会发送 Cloud Pub/Sub 通知,表明客户正在请求账号。您的应用必须批准该请求。在此 Codelab 中,您将在收到 Cloud Pub/Sub 消息时批准账号请求。

创建用于存储账号信息的数据库

在此 Codelab 中,我们将使用一个简单的 JSON 数据库来跟踪客户账号和购买交易。

如需测试此示例,请在工作站上的任意位置创建一个包含空 JSON 对象的文件:

{}

PROCUREMENT_CODELAB_DATABASE 环境变量设置为此文件的完整路径:

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

用于读取和写入数据库的模块位于 python3/impl/database 中。

示例实现使用的架构可扩展,如果您要将多个产品与 Google Cloud Marketplace 集成,则可以使用此架构。以下是示例应用中订阅了非常好方案的用户的数据库条目示例:

{
   "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"
         }
      }
   }
}

在最终实现中,您必须将应用与自己的数据库相关联,以便将客户的 Google Cloud Marketplace 账号与您自己的客户资源相关联。

批准账号

如需批准账号请求,请运行以下命令:

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

用于批准账号的示例代码位于 impl/step_2_account 中。

示例实现使用 Procurement,该类负责处理与 Procurement API 的互动。以下是其 get_account()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()

在此 Codelab 中,在 Procurement 服务中,提供商 ID 为 DEMO-YOUR_PROJECT_ID,其中 YOUR_PROJECT_ID 是您创建的项目。与 Procurement API 交互时,账号名称必须采用以下格式:

providers/DEMO-YOUR_PROJECT_ID/accounts/account-id

接下来,您需要批准授权,即客户购买记录。

6. 批准授权

当客户在 Google Cloud Marketplace 中选择订阅方案时,系统会创建一个账号,然后立即创建一个新的授权请求。授权表示购买的服务。客户必须先获得授权,然后才能开始使用服务。您需要批准授权请求,然后为客户设置服务,以便客户开始使用。

当示例应用收到包含 eventType ENTITLEMENT_CREATION_REQUESTED 的 Cloud Pub/Sub 消息时,系统会批准相应授权,应用必须等待 ENTITLEMENT_ACTIVE 消息来记录数据库中的授权,然后为客户设置资源。

如需创建授权,请运行以下命令:

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

用于批准授权的代码位于示例实现中。

接下来,您将了解如何处理客户要求更改其订阅方案的情况。

7. 批准对使用权的更改

如果您的服务提供多种方案,则必须处理客户的请求,因为他们可能希望升级或降级现有方案。

如果您的服务只有一个方案,请跳至“处理已取消的购买交易”。

对于用户而言,无论是首次启用授权,还是在更改方案后启用授权,在技术上都没有区别。因此,示例实现针对这两种情况共用一个 handleActiveEntitlement() 方法。此方法会检查传入消息中是否存在与授权相关的事件:

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)

以下代码段用于检查 eventType 是否为 ENTITLEMENT_PLAN_CHANGE_REQUESTEDENTITLEMENT_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

在最终实现中,当授权恢复为 ENTITLEMENT_ACTIVE 状态时,监听器方法应更新数据库以反映相应变化,并执行任何必要的配置。

根据您与合作伙伴工程师一起设置产品的方式,您的服务可能不允许在结算周期结束前降级或取消。在这种情况下,即使获得批准,方案更改仍会处于待处理状态,但只有在方案更改完成后,授权才会恢复到 ENTITLEMENT_ACTIVE 状态。

如需查看用于检查和批准授权更改的代码,请参阅示例实现

接下来,您需要处理客户取消购买的情况。

8. 处理已取消的购买交易

客户可以选择取消购买交易。根据您与合作伙伴工程师一起设置产品的方式,取消操作可能会立即生效,也可能会在结算周期结束时生效。

当客户取消购买交易时,系统会发送一条包含 eventType ENTITLEMENT_PENDING_CANCELLATION 的消息。如果您已将商品设置为立即处理取消请求,系统会在不久后发送一封包含 eventType ENTITLEMENT_CANCELLED 的电子邮件。

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

您的服务必须等待 ENTITLEMENT_CANCELLED 消息,然后从数据库中移除相应授权,并为客户关闭服务。

取消授权后,系统会从 Google 的系统中删除相应授权,并发送一条包含 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

如需查看用于取消授权的代码,请参阅示例实现

9. 发送使用情况报告

某些服务具有基于使用情况的组件,Google 需要了解客户对服务的使用情况,才能向客户收取正确的费用。您的服务必须通过 Google Service Control API 报告使用情况。

如果您的服务没有基于使用情况的组件,请跳过本部分。

如需详细了解如何发送使用情况报告,请参阅初始配置文档

使用情况报告应每小时发送到 Google Service Control API。在此 Codelab 中,报告是通过一个脚本发送的,您可以将该脚本安排为 Cron 作业。该脚本会将上次使用情况报告的时间存储在数据库中,并将其用作衡量使用情况的开始时间。

该脚本会检查服务的每个有效客户,并使用客户授权的 consumer_id 字段向 Google Service Control 发送使用情况报告。然后,脚本会更新客户的数据库条目,将 last_report_time 设置为刚刚发送的使用情况报告的结束时间。

Google Service Control 提供两种方法:checkreport。前者应始终在调用后者之前立即调用。如果前者有任何错误,则应停用客户的服务,直到错误修复为止。

给定权益的所有用量都计入单个 usageReportingId。不过,对于 SaaS 产品,此用量会与 Google Cloud 结算中的 [Charges not specific to a project] 专列项相关联。如果您的 SaaS 产品可能会在客户的组织内广泛共享,并且您希望支持费用归属,我们建议您的所有服务都在其用量报告 operation 中包含可选的 userLabels 字段。

Google Cloud Marketplace 会预留 cloudmarketplace.googleapis.com/resource_name 和 cloudmarketplace.googleapis.com/container_name 标签键。这些标签旨在捕获原生服务和资源层次结构中的使用情况上下文。这些资源的客户分配名称将作为标签值包含在使用情况报告中。我们建议您在用量报告中默认添加这些标签。

标签键

标签值

说明

cloudmarketplace.googleapis.com/resource_name

RESOURCE_NAME

与用量指标关联的资源的名称。

cloudmarketplace.googleapis.com/container_name

CONTAINER_NAME

资源容器的名称。

以下代码段报告了演示应用的用量,并将 SaaS 产品的用量归因于客户分配的名为 products_db 的资源。在此 Codelab 中,service_nameisaas-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)

如需查看完整代码,请参阅此脚本的示例实现。如需生成使用情况报告示例,请运行以下命令:

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

10. 恭喜!

您了解了 SaaS 解决方案如何与 Google Cloud Marketplace 集成,以处理客户账号和授权,以及如何针对服务报告用量。如需了解完整的集成步骤,请参阅后端集成文档。

清理

如果您不再打算使用以下资源,请将其删除:

  • Cloud Pub/Sub 订阅
  • 服务账号及其密钥
  • (可选)您创建的项目
  • (可选)您创建的结算账号

后续步骤

集成前端

此 Codelab 中的示例会自动批准账号和授权。实际上,您必须将客户定向到您创建的注册页面,以便他们可以在您的系统中创建账号。在用户成功注册后,您必须发出 API 请求来批准其账号和使用权。

如需了解如何集成应用的前端,请参阅 Google Cloud Marketplace 文档

详细了解如何提供 SaaS 解决方案

如需大致了解如何在 Google Cloud Marketplace 上提供 SaaS 解决方案,请参阅提供 SaaS 解决方案