Интегрируйте свое SaaS-решение с API Google Cloud Marketplace с помощью Producer Portal (Python)

1. Введение

SaaS-решения на Google Cloud Marketplace — это программные решения, которые работают на вашей инфраструктуре независимо от местоположения, но счета за них выставляет Google.

В этой лабораторной работе вы настроите базовое SaaS-решение, интегрирующееся с Google Cloud Marketplace, чтобы:

  • Получайте уведомления, когда пользователь регистрируется для получения образца решения.
  • Одобряйте клиентов, желающих зарегистрироваться, и добавляйте их в свою базу данных.
  • Обрабатывайте сценарии, в которых клиенты хотят изменить или отменить свои тарифные планы.
  • Отправляйте отчеты об использовании в Google.

Эта лабораторная работа поможет вам ознакомиться с API-интерфейсами управления закупками и сервисами Google Cloud Marketplace. Обратите внимание, что это руководство не предоставляет полноценную среду для тестирования продукта.

2. Прежде чем начать

  • Используйте Producer Portal, чтобы включить лабораторию кода для вашего проекта, если вы еще этого не сделали.

Прямая ссылка на Producer Portal:

https://console.cloud.google.com/producer-portal?project= ИД_ВАШЕГО_ПРОЕКТА

Чтобы включить практическую работу, нажмите кнопку Включить на панели «Практические работы» в правой части экрана.

  • Установите Python 3 на свой компьютер со следующими модулями:
  • Клиентские API Google на Python .
  • Клиентская библиотека google-cloud-pubsub .

Для установки модулей 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 идентификатор этого проекта:
  • Линукс:
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
  • Окна:
set GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID
  • Задайте для переменной среды GOOGLE_APPLICATION_CREDENTIALS полный путь к загруженному файлу:
  • Линукс:
export GOOGLE_APPLICATION_CREDENTIALS="[YOUR_MACHINE]/path/service-account-key.json"
  • Окна:
set GOOGLE_APPLICATION_CREDENTIALS=[YOUR_MACHINE]/path/service-account-key.json
  • Чтобы просмотреть пример решения в Google Cloud Marketplace, посетите портал Producer и выберите продукт Codelab на панели Codelabs. Вы также можете получить доступ к решению напрямую по адресу https://console.cloud.google.com/marketplace/product/DEMO- YOUR_PROJECT_ID /isaas-codelab
  • В консоли Google Cloud Console в новом проекте включите API Partner Procurement .

Затем настройте бэкэнд для примера решения.

3. Интеграция с Google Cloud Marketplace

На высоком уровне вы интегрируете пример решения с Google Cloud Marketplace следующими способами:

  • Интегрируйтесь с Cloud Pub/Sub, чтобы получать уведомления из Google Cloud Marketplace, например, когда пользователь регистрируется в вашем решении. Ваш инженер-партнер создаёт тему в Cloud Pub/Sub, на которую вам необходимо подписаться для получения уведомлений.
  • Интеграция с API Partner Procurement для создания учётных записей для новых клиентов. API Partner Procurement используется для обновления учётных записей при выборе, изменении или отмене пользователями своих тарифных планов. Для интеграции с API вам потребуется создать собственную клиентскую библиотеку.
  • Интеграция с Google Service Control для предоставления отчетов об использовании.

4. Подпишитесь на тему Cloud Pub/Sub.

Когда пользователь выбирает план подписки, вы получаете уведомление от Google Cloud Marketplace через тему Cloud Pub/Sub.

Чтобы прослушивать сообщения в теме Cloud Pub/Sub, необходимо сначала создать подписку.

Для создания подписки используйте скрипт create_subscription.py :

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

Чтобы увидеть подписку, откройте панель управления Cloud Pub/Sub в Cloud Console:

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

Попробуйте тестовый запрос на подписку

Чтобы протестировать этот пример приложения в качестве пользователя, откройте продукт Codelab в Marketplace по адресу https://console.cloud.google.com/marketplace/product/DEMO-YOUR_PROJECT_ID /isaas-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 создает от имени клиента.

Первый ресурс — это ресурс учётной записи . Учётная запись представляет собой связь клиента с вашим продуктом. Вам необходимо сохранить идентификатор учётной записи клиента в базе данных, чтобы сопоставить связь между его учётной записью Google и учётной записью вашего сервиса.

Когда клиент выбирает тарифный план, Google Cloud Marketplace отправляет уведомление Cloud Pub/Sub о том, что клиент запрашивает учётную запись. Ваше приложение должно одобрить запрос. В этой лабораторной работе вы одобрите запросы на учётные записи при получении сообщений Cloud Pub/Sub.

Создать базу данных для информации об учетной записи

Для этой лабораторной работы мы используем простую базу данных JSON, которая может отслеживать учетные записи и покупки клиентов.

Чтобы протестировать этот пример, создайте файл с пустым объектом JSON в любом месте на вашей рабочей станции:

{}

Задайте для переменной среды PROCUREMENT_CODELAB_DATABASE полный путь к этому файлу:

  • Линукс:
export PROCUREMENT_CODELAB_DATABASE="YOUR_MACHINE/path/EMPTY_JSON_OBJECT.json"
  • Окна:
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 , который отвечает за взаимодействие с 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()

Для этой практической работы в сервисе закупок идентификатор поставщика — DEMO- YOUR_PROJECT_ID , где YOUR_PROJECT_ID — это созданный вами проект. При взаимодействии с API закупок имя учётной записи должно иметь следующий формат:

providers/DEMO-YOUR_PROJECT_ID/accounts/account-id

Затем вы утверждаете право , которое представляет собой запись о покупке клиента.

6. Утвердить право

Когда клиент выбирает тарифный план в Google Cloud Marketplace, создаётся учётная запись, а затем сразу же создаётся новый запрос на предоставление прав . Право на предоставление прав представляет собой покупку услуги. Прежде чем клиент сможет начать пользоваться услугой, необходимо одобрить запрос на предоставление прав, а затем настроить услугу для клиента.

Когда пример приложения получает сообщение Cloud Pub/Sub с eventType ENTITLEMENT_CREATION_REQUESTED , право утверждается, и приложение должно дождаться сообщения 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 получать информацию об использовании сервиса клиентами, чтобы списывать с них корректную сумму. Ваш сервис должен сообщать об использовании через API Google Service Control.

Если в вашей службе нет компонентов, основанных на использовании, пропустите этот раздел.

Подробную информацию об отправке отчетов об использовании см. в документации по подключению .

Отчёты об использовании должны отправляться в API Google Service Control ежечасно. В этой лабораторной работе отчёты отправляются с помощью скрипта, который можно запланировать как cron-задание. Скрипт сохраняет время последнего отчёта об использовании в базе данных и использует его в качестве времени начала измерения использования.

Скрипт проверяет каждого активного клиента сервиса и отправляет отчёт об использовании в Google Service Control, используя поле consumer_id в его праве. Затем скрипт обновляет запись в базе данных для клиента, добавляя в поле last_report_time время окончания только что отправленного отчёта об использовании.

Google Service Control предоставляет два метода: check и report . Первый всегда следует вызывать непосредственно перед вызовом второго. Если в первом обнаружены ошибки, службу клиента следует отключить до их устранения.

Все данные об использовании для данного права доступа приписываются одному идентификатору usageReportingId . Однако для SaaS-продуктов это использование связано с позицией [Charges not specific to a project] в Google Cloud Billing. Если ваш 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

ИМЯ_КОНТЕЙНЕРА

Имя контейнера ресурсов.

В следующем фрагменте кода сообщается об использовании демонстрационного приложения и приписывается использование 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-решений

Обзор предложений SaaS-решений на Google Cloud Marketplace см. в разделе Предложение SaaS-решений .