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 3,并包含以下模块:
- Python 版 Google 客户端 API。
google-cloud-pubsub
客户端库。
如需安装 Python 模块,请使用以下命令:
pip install --upgrade google-api-python-client google-cloud-pubsub
- 使用以下命令克隆或下载此 Codelab 的 GitHub 代码库:
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
- 向服务账号
saas-codelab
授予 Pub/Sub Editor 角色。如需了解授予和管理角色的步骤,请参阅授予、更改和撤消对资源的访问权限。 - 为服务账号创建并下载 JSON 密钥。如需了解创建密钥的步骤,请参阅创建和管理服务账号密钥。
- 将
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()
方法:
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_REQUESTED
或 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
在最终实现中,当授权恢复为 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 提供两种方法:check
和 report
。前者应始终在调用后者之前立即调用。如果前者有任何错误,则应停用客户的服务,直到错误修复为止。
给定权益的所有用量都计入单个 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_name
为 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)
如需查看完整代码,请参阅此脚本的示例实现。如需生成使用情况报告示例,请运行以下命令:
~/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 解决方案。