使用 Producer Portal (Python) 將軟體即服務 (SaaS) 解決方案與 Google Cloud Marketplace API 整合

1. 簡介

Google Cloud Marketplace 上的軟體即服務 (SaaS) 解決方案是指可在您任何地方的基礎架構上執行的軟體解決方案,但 Google 會向您收取費用。

在本程式碼研究室中,您將設定與 Google Cloud Marketplace 整合的基本軟體即服務 (SaaS) 解決方案,以便:

  • 使用者註冊試用解決方案時接收通知。
  • 核准想註冊的顧客,並將他們新增至資料庫。
  • 處理客戶想變更或取消帳單方案的情況。
  • 將使用報告傳送給 Google。

本程式碼研究室可協助您熟悉 Google Cloud Marketplace 採購程序和服務控制 API。請注意,本指南不會提供完整的產品測試環境。

2. 事前準備

  • 如果尚未啟用,請使用 Producer Portal 為專案啟用程式碼研究室。

Producer Portal 的直接連結如下:

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

如要啟用程式碼研究室,請按一下畫面右側「Codelabs」面板中的「Enable」

如要安裝 Python 模組,請使用下列指令:

pip install --upgrade google-api-python-client google-cloud-pubsub
  • 使用下列指令,複製或下載本程式碼研究室的 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
  • 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 product」。您也可以直接前往 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 專案,然後選擇訂閱方案。

如要查看選擇方案時傳送的 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 採購服務代表客戶建立的資源。

第一個是「account」資源。帳戶代表顧客與產品的連結。您必須在資料庫中儲存客戶的採購帳戶 ID,才能對應客戶的 Google 帳戶與服務帳戶之間的關係。

在客戶選擇方案時,Google Cloud Marketplace 會傳送 Cloud Pub/Sub 通知,指出客戶正在要求帳戶。應用程式必須核准要求。在本程式碼研究室中,您會在收到 Cloud Pub/Sub 訊息時核准帳戶要求。

建立帳戶資訊資料庫

在本程式碼研究室中,我們會使用簡單的 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 整合,可以擴充範例實作中使用的結構定義。以下是使用者在範例應用程式中訂閱「Very Good」方案的資料庫項目範例:

{
   "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()

在本程式碼研究室中,供應商 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。在本程式碼研究室中,報表是透過指令碼傳送,您可以將指令碼排定為 Cron 工作。指令碼會在資料庫中儲存上次用量報告的時間,並將該時間做為測量用量的開始時間。

這項指令碼會檢查服務的每位有效客戶,並使用客戶授權的 consumer_id 欄位,將用量報告傳送至 Google Service Control。然後,指令碼會更新顧客的資料庫項目,將 last_report_time 設為剛傳送的使用量報告結束時間。

Google Service Control 提供兩種方法:checkreport。前者應一律在呼叫後者之前立即呼叫。如果前者有任何錯誤,應停用客戶的服務,直到修正為止。

特定授權的所有用量都會歸因於單一 usageReportingId。不過,如果是 SaaS 產品,這類用量會與 Google Cloud Billing 中的 [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 的客戶指派資源。在本程式碼研究室中,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 訂閱項目
  • 服務帳戶和金鑰
  • (選用) 您建立的專案
  • (選用) 您建立的帳單帳戶

後續步驟

整合前端

本程式碼研究室中的範例會自動核准帳戶和權利。實際上,系統會將顧客導向您建立的註冊頁面,以便在您的系統中建立帳戶。註冊成功後,您必須發出 API 要求,核准他們的帳戶和權利。

如要瞭解如何整合應用程式前端,請參閱 Google Cloud Marketplace 說明文件

進一步瞭解如何提供 SaaS 解決方案

如需在 Google Cloud Marketplace 上提供軟體即服務 (SaaS) 解決方案的總覽,請參閱「提供軟體即服務 (SaaS) 解決方案」一文。