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

コードラボを有効にするには、画面右側の [Codelabs] パネルで [Enable] をクリックします。

  • 次のモジュールを使用して、マシンに 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
  • 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 プロダクトを開きます。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 Procurement サービスが顧客に代わって作成するリソースの処理を開始する必要があります。

1 つ目は account リソースです。アカウントは、お客様のプロダクトへの接続を表します。お客様の Google アカウントとお客様のサービスのアカウントの関係をマッピングするには、お客様の調達アカウント ID をデータベースに保存する必要があります。

顧客がプランを選択すると、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 と統合する場合に拡張できるスキーマを使用します。以下は、サンプルアプリの 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 API とのやり取りを処理する Procurement クラスを使用します。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 では、調達サービスでプロバイダ 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. エンタイトルメントの変更を承認する

サービスに複数のプランがある場合は、既存のプランのアップグレードまたはダウングレードを希望するお客様からのリクエストを処理する必要があります。

サービスにプランが 1 つしかない場合は、購入のキャンセルを処理するに進みます。

利用資格が初めて有効になった場合と、プラン変更後に有効になった場合との間に技術的な違いはありません。そのため、実装例には、両方のケースで共有される 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)

次のスニペットは、eventTypeENTITLEMENT_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 を介して使用状況を報告する必要があります。

サービスに使用量ベースのコンポーネントがない場合は、このセクションをスキップしてください。

使用状況レポートの送信について詳しくは、オンボーディングのドキュメントをご覧ください。

使用状況レポートは、1 時間ごとに Google Service Control API に送信する必要があります。この Codelab では、レポートは cron ジョブとしてスケジュール設定できるスクリプトを使用して送信されます。スクリプトは、最後の使用状況レポートの時刻をデータベースに保存し、それを使用状況の測定の開始時刻として使用します。

このスクリプトは、サービスの各アクティブな顧客をチェックし、顧客利用資格の consumer_id フィールドを使用して使用状況レポートを Google Service Control に送信します。スクリプトは、顧客のデータベース エントリを更新して、last_report_time を送信したばかりの使用状況レポートの終了時刻に設定します。

Google Service Control は、checkreport という 2 つのメソッドを公開します。前者は、後者の呼び出しの直前に常に呼び出す必要があります。前者にエラーがある場合は、修正されるまでお客様のサービスを無効にする必要があります。

特定のエンタイトルメントのすべての使用は、単一の usageReportingId に帰属します。ただし、SaaS プロダクトの場合、この使用量は Google Cloud Billing の [Charges not specific to a project] 項目に関連付けられます。SaaS プロダクトがお客様の組織内で広く共有される可能性があり、費用アトリビューションをサポートする場合は、すべてのサービスで使用状況レポートのオペレーションにオプションの 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 ソリューションの提供をご覧ください。