始める前に
API 設定 Codelab を完了して Google Cloud プロジェクトを設定し、Cloud Channel API を呼び出すサービス アカウントを作成します。
チャネル サービスのオペレーションについてご覧ください。
概要
Google Cloud の利用資格を持つ顧客をプロビジョニングするには、いくつかの API 呼び出しが必要になります。次の図は、顧客をプロビジョニングするための手順の概要を示しています。
ステップ 1: 認証済みの認証情報を持つサービス オブジェクトを作成する
クライアント ライブラリの使用
この Codelab では、Cloud Channel API のクライアント ライブラリのいずれかを使用していることを前提としています。
統合には Google クライアント ライブラリを使用することをおすすめします。これらのライブラリは、言語固有の自然なインターフェースを提供し、HTTP ではなく RPC を使用してパフォーマンスを向上させ、フィールドのデフォルト値を設定します。
ライブラリをインストールするには:
C++
C++ クライアント ライブラリをインストールするには、C++ 開発環境の設定をご覧ください。
C#
Visual Studio 2017 以降を使用している場合は、nuget パッケージ マネージャーのウィンドウを開き、次のように入力します。
Install-Package Google.Cloud.Channel.V1
.NET Core コマンドライン インターフェースを使用して依存関係をインストールしている場合は、次のコマンドを実行します。
dotnet add package Google.Cloud.Channel.V1
Go
go mod init YOUR_MODULE_NAME
go get cloud.google.com/go/channel/apiv1
Java
Maven を使用している場合は、以下を pom.xml
ファイルに追加します。BOM の詳細については、Google Cloud Platform ライブラリ BOM をご覧ください。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>20.9.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-channel</artifactId>
<version>2.3.0</version>
</dependency>
Gradle を使用している場合は、次のものを依存関係に追加します。
implementation group: 'com.google.cloud', name: 'google-cloud-channel', version: '2.3.0'
VS Code、IntelliJ、または Eclipse を使用している場合は、次の IDE プラグインでプロジェクトにクライアント ライブラリを追加できます。
プラグインは、サービス アカウントのキー管理などの追加機能も提供します。詳細は各プラグインのドキュメントをご覧ください。
Node.js
npm install --save @google-cloud/channel
PHP
composer require google/cloud-channel
Python
pip install google-cloud-channel
Ruby
gem install google-cloud-channel
クライアント ライブラリを使用しない場合は、認証を処理するための小規模なクライアント ライブラリを確認することをおすすめします。認証レイヤを最初から書き直すことはおすすめしません。
認証用の認証情報を設定する
Cloud Channel API は、以下を必要とする認証のタイプを使用します。
- サービス アカウントと、それに対応する JSON キーファイル。
- サービス アカウントのクライアントでドメイン全体の委任を使用して権限を借用する販売パートナー ドメインの特権管理者。
前提条件を満たしていない場合は、API 設定の Codelab に沿って操作してください。詳しくは、サービス アカウントの OAuth 2.0 をご覧ください。
次のコードで、自分の情報を使用してこれらの変数を入力します。
jsonKeyFile
: サービス アカウントの作成時に生成された JSON キーファイルへのパス。resellerAdminUser
: 販売パートナー ドメインの特権管理者のメールアドレス。accountId
: Partner Sales Console の [設定] ページにあるアカウント ID。customerDomain
: エンドユーザーのドメイン。
C#
using Google.Apis.Auth.OAuth2; using Google.Api.Gax; using Google.Cloud.Billing.V1; // optional using Google.Cloud.Channel.V1; using Google.Cloud.Iam.V1; // optional using Google.Type; using Newtonsoft.Json; using System; using System.Linq; namespace Codelab { class Program { /***************** REPLACE WITH YOUR OWN VALUES ********************************/ private static readonly string jsonKeyFile = "path/to/json_key_file.json"; private static readonly string resellerAdminUser = "admin@yourresellerdomain.com"; private static readonly string accountId = "C012345"; private static readonly string customerDomain = "example.com"; /*******************************************************************************/ private static readonly string accountName = "accounts/" + accountId; private static CloudChannelServiceClient client; static void Main(string[] args) { // Set up credentials with user impersonation ICredential credential = GoogleCredential.FromFile(jsonKeyFile) .CreateScoped(CloudChannelServiceClient.DefaultScopes) .CreateWithUser(resellerAdminUser); // Create the API client client = new CloudChannelServiceClientBuilder { TokenAccessMethod = credential.GetAccessTokenForRequestAsync }.Build();
Go
package main import ( "context" "fmt" "io/ioutil" billing "cloud.google.com/go/billing/apiv1" // optional channel "cloud.google.com/go/channel/apiv1" "golang.org/x/oauth2/google" "google.golang.org/api/iterator" "google.golang.org/api/option" channelpb "google.golang.org/genproto/googleapis/cloud/channel/v1" iampb "google.golang.org/genproto/googleapis/iam/v1" // optional "google.golang.org/genproto/googleapis/type/postaladdress" "google.golang.org/protobuf/encoding/protojson" ) // ############## REPLACE WITH YOUR OWN VALUES #################### const jsonKeyFile = "path/to/json_key_file.json" const resellerAdminUser = "admin@yourresellerdomain.com" const accountID = "C012345" const customerDomain = "example.com" // ################################################################ const accountName = "accounts/" + accountID func main() { ctx := context.Background() // set up credentials with user impersonation jsonKey, _ := ioutil.ReadFile(jsonKeyFile) jwt, _ := google.JWTConfigFromJSON(jsonKey, "https://www.googleapis.com/auth/apps.order") jwt.Subject = resellerAdminUser tokenSource := jwt.TokenSource(ctx) // create the API client client, _ := channel.NewCloudChannelClient(ctx, option.WithTokenSource(tokenSource))
Java
import com.google.api.gax.core.FixedCredentialsProvider; import com.google.api.gax.longrunning.OperationFuture; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.channel.v1.CloudChannelServiceClient; import com.google.cloud.channel.v1.CloudChannelServiceSettings; import com.google.cloud.channel.v1.CreateCustomerRequest; import com.google.cloud.channel.v1.CreateEntitlementRequest; import com.google.cloud.channel.v1.Customer; import com.google.cloud.channel.v1.Entitlement; import com.google.cloud.channel.v1.ListOffersRequest; import com.google.cloud.channel.v1.Offer; import com.google.cloud.channel.v1.OperationMetadata; import com.google.cloud.channel.v1.Parameter; import com.google.cloud.channel.v1.Value; import com.google.gson.Gson; import com.google.type.PostalAddress; import java.io.FileInputStream; import java.io.IOException; import java.util.Iterator; import java.util.concurrent.ExecutionException; // optional import java.util.ArrayList; import java.util.List; import com.google.cloud.billing.v1.CloudBillingClient; import com.google.cloud.billing.v1.CloudBillingSettings; import com.google.iam.v1.Binding; import com.google.iam.v1.Policy; // ... public class Codelab { /***************** REPLACE WITH YOUR OWN VALUES ********************************/ public static final String JSON_KEY_FILE = "path/to/json_key_file.json"; public static final String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com"; public static final String ACCOUNT_ID = "C012345"; public static final String CUSTOMER_DOMAIN = "example.com"; /*******************************************************************************/ public static final String ACCOUNT_NAME = "accounts/" + ACCOUNT_ID; private static CloudChannelServiceClient client; private static final Gson gson = new Gson(); public static void main(String[] args) throws IOException, ExecutionException, InterruptedException { // Set up credentials with user impersonation FileInputStream jsonKeyFileSteam = new FileInputStream(JSON_KEY_FILE); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(jsonKeyFileSteam) .createScoped("https://www.googleapis.com/auth/apps.order") .createDelegated(RESELLER_ADMIN_USER); CloudChannelServiceSettings clientSettings = CloudChannelServiceSettings.newBuilder() .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); // Create the API client client = CloudChannelServiceClient.create(clientSettings);
Node.js
const {JWT} = require('google-auth-library'); const {grpc} = require('google-gax'); const {CloudChannelServiceClient} = require('@google-cloud/channel'); // ############## REPLACE WITH YOUR OWN VALUES #################### const jsonKeyFile = 'path/to/json_key_file.json'; const resellerAdminUser = 'admin@yourresellerdomain.com'; const accountId = 'C012345'; const customerDomain = 'example.com'; // ################################################################ const accountName = `accounts/${accountId}`; // Set up credentials with user impersonation const authClient = new JWT({ keyFile: jsonKeyFile, scopes: ['https://www.googleapis.com/auth/apps.order'], subject: resellerAdminUser, }); const sslCreds = grpc.credentials.combineChannelCredentials( grpc.credentials.createSsl(), grpc.credentials.createFromGoogleCredential(authClient) ); // Create the API client const client = new CloudChannelServiceClient({sslCreds});
PHP
require 'vendor/autoload.php'; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Cloud\Channel; // ############## REPLACE WITH YOUR OWN VALUES #################### $JSON_KEY_FILE = 'path/to/json_key_file.json'; $RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'; $ACCOUNT_ID = 'C012345'; $CUSTOMER_DOMAIN = 'example.com'; // ################################################################ $ACCOUNT_NAME = 'accounts/' . $ACCOUNT_ID; // Set up credentials with user impersonation $credentials = new ServiceAccountCredentials( 'https://www.googleapis.com/auth/apps.order', /* $scope */ $JSON_KEY_FILE, /* $keyFile */ $RESELLER_ADMIN_USER /* $sub */ ); // Create the API client $client = new Channel\V1\CloudChannelServiceClient([ 'credentials' => $credentials ]);
Python
from google.cloud import channel from google.oauth2 import service_account # optional from google.cloud import billing from google.iam.v1 import policy_pb2 ############## REPLACE WITH YOUR OWN VALUES #################### JSON_KEY_FILE = "path/to/json_key_file.json" RESELLER_ADMIN_USER = "admin@yourresellerdomain.com" ACCOUNT_ID = "C012345" CUSTOMER_DOMAIN = "example.com" ################################################################ ACCOUNT_NAME = "accounts/" + ACCOUNT_ID # Set up credentials with user impersonation credentials = service_account.Credentials.from_service_account_file( JSON_KEY_FILE, scopes=["https://www.googleapis.com/auth/apps.order"]) credentials_delegated = credentials.with_subject(RESELLER_ADMIN_USER) # Create the API client client = channel.CloudChannelServiceClient(credentials=credentials_delegated)
Ruby
require 'google-cloud-channel' require 'google-cloud-billing' # Optional require 'google/iam/v1/policy_pb' # Optional ################## REPLACE WITH YOUR OWN VALUES ################################ JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json' RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com' ACCOUNT_ID = 'C012345' CUSTOMER_DOMAIN = 'example.com' ################################################################################ ACCOUNT_NAME = "accounts/#{ACCOUNT_ID}" # Set up credentials with user impersonation credentials = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: File.open(JSON_PRIVATE_KEY_FILE), scope: 'https://www.googleapis.com/auth/apps.order') credentials.sub = RESELLER_ADMIN_USER # Create the API client CLIENT = Google::Cloud::Channel::cloud_channel_service do |config| config.credentials = credentials end
ステップ 2: オファーのリストからオファーを選択する
以下のサンプルコードでは、Google Cloud Platform
の最初のオファーを選択します。特定の Cloud Billing アカウント ID(billingAccounts/...
形式)のオファーを選択する場合は、plan.billingAccount
フィールドでオファーをフィルタリングできます。
C#
PagedEnumerable<ListOffersResponse, Offer> offers = client.ListOffers(new ListOffersRequest { Parent = accountName }); // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration Offer selectedOffer = offers.FirstOrDefault( o => o.Sku.MarketingInfo.DisplayName == "Google Cloud Platform"); Console.WriteLine("=== Selected offer"); Console.WriteLine(JsonConvert.SerializeObject(selectedOffer));
Go
var selectedOffer *channelpb.Offer req := &channelpb.ListOffersRequest{ Parent: accountName, } it := client.ListOffers(ctx, req) // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another and // is not a recommended model for your production integration. for { offer, err := it.Next() if err == iterator.Done { break } if offer.Sku.MarketingInfo.DisplayName == "Google Cloud Platform" { selectedOffer = offer break } } fmt.Println("=== Selected offer") fmt.Println(protojson.Format(selectedOffer))
Java
ListOffersRequest request = ListOffersRequest.newBuilder().setParent(ACCOUNT_NAME).build(); // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration CloudChannelServiceClient.ListOffersPagedResponse response = client.listOffers(request); Offer selectedOffer = Offer.newBuilder().build(); Iterator<Offer> iterator = response.iterateAll().iterator(); while (iterator.hasNext()) { Offer offer = iterator.next(); String skuName = offer.getSku().getMarketingInfo().getDisplayName(); if (skuName.equals("Google Cloud Platform")) { selectedOffer = offer; break; } } System.out.println("=== Selected offer"); System.out.println(gson.toJson(selectedOffer));
Node.js
const [offers] = await client.listOffers({ parent: accountName, }); // For the purpose of this codelab, the code lists all offers and selects // the first offer for the Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration const selectedOffer = offers.find(o => { return o.sku.marketingInfo.displayName === 'Google Cloud Platform'; }); console.log('=== Selected offer'); console.info(selectedOffer);
PHP
$offers = $client->listOffers($ACCOUNT_NAME /* parent */); // For the purpose of this codelab, the code lists all offers and selects // the first offer for the Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration $sampleSku = 'Google Cloud Platform'; foreach ($offers as $offer) { if ($offer->getSku()->getMarketingInfo()->getDisplayName() == $sampleSku) { $selectedOffer = $offer; break; } } print '=== Selected offer' . PHP_EOL; print $selectedOffer->serializeToJsonString() . PHP_EOL;
Python
request = channel.ListOffersRequest(parent=ACCOUNT_NAME) offers = client.list_offers(request) # For the purpose of this codelab, the code lists all offers and selects # the first offer for Google Cloud Platform. # This is needed because offerIds vary from one account to another, # but this is not a recommended model for your production integration selected_offer = None for offer in offers: if offer.sku.marketing_info.display_name == "Google Cloud Platform": selected_offer = offer break print("=== Selected offer") print(selected_offer)
Ruby
# For the purpose of this codelab, the code lists all offers and selects # the first offer for Google Cloud Platform. # This is needed because offerIds vary from one account to another, # but this is not a recommended model for your production integration request = Google::Cloud::Channel::V1::ListOffersRequest.new({ parent: ACCOUNT_NAME }) offers = CLIENT.list_offers(request) sample_offer = 'Google Cloud Platform' offer = offers.detect { |offer| offer.sku.marketing_info.display_name == sample_offer } puts('=== Selected offer') puts(offer.inspect)
ステップ 3: 顧客を作成する
利用資格を作成する前に、再販される顧客のチャネル サービスの顧客を作成する必要があります。
C#
// Create the Customer resource CreateCustomerRequest request = new CreateCustomerRequest { Parent = accountName, Customer = new Customer { OrgDisplayName = "Acme Corp", OrgPostalAddress = new PostalAddress { AddressLines = { "1800 Amphibious Blvd" }, PostalCode = "94045", RegionCode = "US" }, Domain = customerDomain, // Optional. Add the CRM ID for this customer. CorrelationId = "CRMID012345" } }; Customer customer = client.CreateCustomer(request); Console.WriteLine("=== Created customer with id " + customer.Name); Console.WriteLine(JsonConvert.SerializeObject(customer));
Go
// Create the Customer resource req := &channelpb.CreateCustomerRequest{ Parent: accountName, Customer: &channelpb.Customer{ OrgDisplayName: "Acme Corp", OrgPostalAddress: &postaladdress.PostalAddress{ AddressLines: []string{"1800 Amphibious Blvd"}, PostalCode: "94045", RegionCode: "US", }, Domain: customerDomain, // Optional. Add the CRM ID for this customer. CorrelationId: "CRMID012345", // Distributors need to pass the following value // ChannelPartnerId: channelPartnerLinkId }, } customer, _ := client.CreateCustomer(ctx, req) fmt.Println("=== Created customer with id " + customer.Name) fmt.Println(protojson.Format(customer))
Java
// Create the Customer resource PostalAddress postalAddress = PostalAddress.newBuilder() .addAddressLines("1800 Amphibious Blvd") .setPostalCode("94045") .setRegionCode("US") .build(); CreateCustomerRequest request = CreateCustomerRequest.newBuilder() .setParent(ACCOUNT_NAME) .setCustomer( Customer.newBuilder() .setOrgDisplayName("Acme Corp") .setOrgPostalAddress(postalAddress) .setDomain(CUSTOMER_DOMAIN) // Optional. Add the CRM ID for this customer. .setCorrelationId("CRMID012345") // Distributors need to pass the following field // .setChannelPartnerId(channelPartnerLinkId) .build()) .build(); Customer customer = client.createCustomer(request); System.out.println("=== Created customer with id " + customer.getName()); System.out.println(gson.toJson(customer));
Node.js
// Create the Customer resource const [customer] = await client.createCustomer({ parent: accountName, customer: { orgDisplayName: 'Acme Corp', orgPostalAddress: { addressLines: ['1800 Amphibious Blvd'], postalCode: '94045', regionCode: 'US', }, domain: customerDomain, // Optional. Add the CRM ID for this customer. correlationId: "CRMID012345", // Distributors need to pass the following field // channelPartnerId: channelPartnerLinkId }, }); console.log(`=== Created customer with id ${customer.name}`); console.info(customer);
PHP
// Create the Customer resource $customer = $client->createCustomer( $ACCOUNT_NAME /* parent */, new Channel\V1\Customer([ 'org_display_name' => 'Acme Corp', 'org_postal_address' => new Google\Type\PostalAddress([ 'address_lines' => ['1800 Amphibious Blvd'], 'postal_code' => '94045', 'region_code' => 'US', ]), 'domain' => $CUSTOMER_DOMAIN, // Optional. Add the CRM ID for this customer. 'correlation_id' => 'CRMID012345', // Distributors need to pass the following field // 'channel_partner_id' => $channelPartnerLinkId ]) ); print '=== Created customer with id ' . $customer->getName() . PHP_EOL; print $customer->serializeToJsonString() . PHP_EOL;
Python
# Create the Customer resource request = channel.CreateCustomerRequest( parent=ACCOUNT_NAME, customer={ "org_display_name": "Acme Corp", "domain": CUSTOMER_DOMAIN, "org_postal_address": { "address_lines": ["1800 Amphibious Blvd"], "postal_code": "94045", "region_code": "US" }, # Optional. Add the CRM ID for this customer. "correlation_id": "CRMID012345" }) # Distributors need to also pass the following field for the `customer` # "channel_partner_id": channel_partner_link_id customer = client.create_customer(request) print("=== Created customer with id ", customer.name) print(customer)
Ruby
# Create the Customer resource request = Google::Cloud::Channel::V1::CreateCustomerRequest.new( parent: ACCOUNT_NAME, customer: { 'org_display_name': 'Acme Corp', 'domain': CUSTOMER_DOMAIN, 'org_postal_address': { 'address_lines': ['1800 Amphibious Blvd'], 'postal_code': '94045', 'region_code': 'US' }, # Optional. Add the CRM ID for this customer. 'correlation_id': 'CRMID012345' }) # Distributors need to also pass the following field for the `customer` # "channel_partner_id": channel_partner_link_id customer = CLIENT.create_customer(request) puts("=== Created customer with id " + customer.name) puts(customer.inspect)
ステップ 4: 利用資格を作成する
顧客を作成したら、利用資格をプロビジョニングできます。
C#
// This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" string displayName = "Reseller XYZ - Acme corp"; CreateEntitlementRequest request = new CreateEntitlementRequest { Parent = customer.Name, Entitlement = new Entitlement { Offer = selectedOffer.Name, Parameters = { new Parameter { Name = "display_name", Value = new Value { StringValue = displayName } } }, // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. PurchaseOrderId = "A codelab test" } }; // This call returns a long-running operation. var operation = client.CreateEntitlement(request); // Wait for the long-running operation and get the result. Entitlement entitlement = operation.PollUntilCompleted().Result; Console.WriteLine("=== Created entitlement"); Console.WriteLine(JsonConvert.SerializeObject(entitlement));
Go
// This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" const displayName = "Reseller XYZ - Acme corp" // This endpoint returns a long-running operation. req := &channelpb.CreateEntitlementRequest{ Parent: customer.Name, Entitlement: &channelpb.Entitlement{ Offer: selectedOffer.Name, Parameters: []*channelpb.Parameter{ { Name: "display_name", Value: &channelpb.Value{ Kind: &channelpb.Value_StringValue{StringValue: displayName}, }, }, }, // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. PurchaseOrderId: "A codelab test", }, } // This endpoint returns a long-running operation. op, _ := client.CreateEntitlement(ctx, req) // Wait for the long-running operation and get the result. entitlement, _ := op.Wait(ctx) fmt.Println("=== Created entitlement") fmt.Println(protojson.Format(entitlement))
Java
// This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" String displayName = "Reseller XYZ - Acme corp"; Entitlement entitlement = Entitlement.newBuilder() .setOffer(selectedOffer.getName()) .addParameters( Parameter.newBuilder() .setName("display_name") .setValue(Value.newBuilder().setStringValue(displayName).build()) .build()) // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. .setPurchaseOrderId("A codelab test") .build(); CreateEntitlementRequest request = CreateEntitlementRequest.newBuilder() .setParent(customer.getName()) .setEntitlement(entitlement) .build(); // This call returns a long-running operation. OperationFuture<Entitlement, OperationMetadata> operation = client.createEntitlementAsync(request); // Wait for the long-running operation and get the result. entitlement = operation.get(); System.out.println("=== Created entitlement"); System.out.println(gson.toJson(entitlement));
Node.js
// This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" const displayName = 'Reseller XYZ - Acme corp'; // This call returns a long-running operation. const [operation] = await client.createEntitlement({ parent: customer.name, entitlement: { offer: selectedOffer.name, parameters: [ { name: 'display_name', value: { stringValue: displayName, }, }, ], // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. purchaseOrderId: 'A codelab test', }, }); // Wait for the long-running operation and get the result. const [entitlement] = await operation.promise(); console.log('=== Created entitlement'); console.info(entitlement);
PHP
// This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" $displayName = 'Reseller XYZ - Acme corp'; // This call returns a long-running operation. $operation = $client->createEntitlement( $customer->getName() /* parent */, new Channel\V1\Entitlement([ 'offer' => $selectedOffer->getName(), 'parameters' => [ new Channel\V1\Parameter([ 'name' => 'display_name', 'value' => new Channel\V1\Value([ 'string_value' => $displayName, ]) ]), ], // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. 'purchase_order_id' => 'A codelab test' ]) ); // Wait for the long-running operation and get the result. $operation->pollUntilComplete(); $entitlement = $operation->getResult(); print '=== Created entitlement' . PHP_EOL; print $entitlement->serializeToJsonString() . PHP_EOL;
Python
# This display name shows on the Google Cloud console when a customer # links the account to their project. # Recommended format: "[Reseller name] - [Customer name]" display_name = "Reseller XYZ - Acme corp" request = channel.CreateEntitlementRequest( parent=customer.name, entitlement={ "offer": selected_offer.name, "parameters": [{ "name": "display_name", "value": { "string_value": display_name } }], # A string of up to 80 characters. # We recommend an internal transaction ID or # identifier for this customer in this field. "purchase_order_id": "A codelab test" }) # This call returns a long-running operation. operation = client.create_entitlement(request) # Wait for the long-running operation and get the result. entitlement = operation.result() print("=== Created entitlement") print(entitlement)
Ruby
# This display name shows on the Google Cloud console when a customer # links the account to their project. # Recommended format: "[Reseller name] - [Customer name]" display_name = 'Reseller XYZ - Acme Corp' request = Google::Cloud::Channel::V1::CreateEntitlementRequest.new( parent: customer.name, entitlement: { offer: selected_offer.name, # Setting 5 seats for this Annual offer parameters: [{ name: 'display_name', value: { string_value: display_name } }], # A string of up to 80 characters. # We recommend an internal transaction ID or # identifier for this customer in this field. purchase_order_id: 'A codelab test' }) # This call returns a long-running operation. operation = CLIENT.create_entitlement(request) # Wait for the long-running operation and get the result. CLIENT.operations_client.wait_operation(Google::Longrunning::WaitOperationRequest .new({ name: operation.name })) operation = CLIENT.operations_client.get_operation(Google::Longrunning::GetOperationRequest .new({ name: operation.name })) entitlement = operation.response puts("=== Created entitlement") puts(entitlement)
省略可: 顧客の請求先アカウントの IAM ポリシーを更新する
利用資格を作成すると、顧客の請求先アカウントがプロビジョニングされます。このアカウントへの明示的なアクセス権を顧客に付与することもできます。
これは、Cloud Billing API を介してプログラムで行うことができます。手順は次のとおりです。
- Google Cloud コンソールで API ライブラリに移動し、Cloud Billing API を有効にします。
- サービス アカウントに、親の請求先アカウントに対する Cloud Billing IAM ロールを付与します。この Codelab では、請求先アカウント管理者(
roles/billing.admin
)を付与することをおすすめしますが、本番環境の統合では、よりきめ細かな権限を使用することができます。アクセス権の付与について詳しくは、Cloud Billing API のアクセス制御ページをご覧ください。
まず、ライブラリをインストールします。
C#
Visual Studio 2017 以降を使用している場合は、nuget パッケージ マネージャーのウィンドウを開き、次のように入力します。
Install-Package Google.Cloud.Billing.V1
.NET Core コマンドライン インターフェースを使用して依存関係をインストールしている場合は、次のコマンドを実行します。
dotnet add package Google.Cloud.Billing.v1
Go
go get cloud.google.com/go/billing/apiv1
Java
インストール手順については、Maven リポジトリをご覧ください。次のコードは、バージョン 1.1.12
でテストされています。
Node.js
npm install --save @google-cloud/nodejs-billing
PHP
composer require google/cloud-billing
Python
pip install google-cloud-billing
Ruby
gem install google-cloud-billing
その後、クライアントをインスタンス化して IAM ポリシーを更新できます。
C#
// Get the name of the customer's billing account from the entitlement String billingAccount = entitlement.ProvisionedService.ProvisioningId; // Create a Cloud Billing API client CloudBillingClient billingClient = new CloudBillingClientBuilder { CredentialsPath = jsonKeyFile }.Build(); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. Policy policy = billingClient.GetIamPolicy(billingAccount); string role = "roles/billing.user"; string member = "user:" + resellerAdminUser; var binding = policy.Bindings.FirstOrDefault(b => b.Role == role); // If the binding already exists, add the user to it, else add a new binding if (binding != null) { binding.Members.Add(member); } else { binding = new Binding { Role = role }; binding.Members.Add(member); policy.Bindings.Add(binding); } // Update the IAM policy SetIamPolicyRequest request = new SetIamPolicyRequest { Resource = billingAccount, Policy = policy }; billingClient.SetIamPolicy(request); Console.WriteLine("=== Set IAM policy"); Console.WriteLine(JsonConvert.SerializeObject(policy));
Go
// Get the name of the customer's billing account from the entitlement billingAccount := entitlement.ProvisionedService.ProvisioningId // Create a Cloud Billing API client client, _ := billing.NewCloudBillingClient(ctx, option.WithCredentialsFile(jsonKeyFile)) // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. getPolicyReq := &iampb.GetIamPolicyRequest{Resource: billingAccount} policy, _ := client.GetIamPolicy(ctx, getPolicyReq) var binding *iampb.Binding const role = "roles/billing.user" const member = "user:" + resellerAdminUser for _, b := range policy.Bindings { if b.Role == role { binding = b break } } // If the binding already exists, add the user to it, else add a new binding if binding != nil { binding.Members = append(binding.Members, member) } else { binding = &iampb.Binding{ Role: role, Members: []string{member}, } policy.Bindings = append(policy.Bindings, binding) } // Update the IAM policy setPolicyReq := &iampb.SetIamPolicyRequest{ Resource: billingAccount, Policy: policy, } client.SetIamPolicy(ctx, setPolicyReq) fmt.Println("=== Set IAM policy") fmt.Println(protojson.Format(policy))
Java
// Get the name of the customer's billing account from the entitlement String billingAccount = entitlement.getProvisionedService().getProvisioningId(); // Create a Cloud Billing API client FileInputStream jsonKeyFileSteam = new FileInputStream(JSON_KEY_FILE); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(jsonKeyFileSteam); CloudBillingSettings clientSettings = CloudBillingSettings.newBuilder() .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); CloudBillingClient client = CloudBillingClient.create(clientSettings); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. Policy policy = client.getIamPolicy(billingAccount); Binding binding = null; int bindingIndex = 0; String role = "roles/billing.user"; String member = "user:" + RESELLER_ADMIN_USER; // getBindingsList() returns an ImmutableList and copying over to an ArrayList so it's mutable. List<Binding> bindings = new ArrayList(policy.getBindingsList()); for (int index = 0; index < bindings.size(); index++) { Binding b = bindings.get(index); if (b.getRole().equals(role)) { binding = b; bindingIndex = index; break; } } // If the binding already exists, add the user to it, else add a new binding Policy.Builder newPolicyBuilder = policy.toBuilder(); if (binding != null) { newPolicyBuilder.setBindings(bindingIndex, binding.toBuilder().addMembers(member).build()); } else { binding = Binding.newBuilder() .setRole(role) .addMembers(member) .build(); newPolicyBuilder.addBindings(binding); } // Update the IAM policy Policy newPolicy = newPolicyBuilder.build(); client.setIamPolicy(billingAccount, newPolicy); System.out.println("=== Set IAM policy"); System.out.println(gson.toJson(newPolicy));
Node.js
// Get the name of the customer's billing account from the entitlement const billingAccount = entitlement.provisionedService.provisioningId; // Create a Cloud Billing API client const {CloudBillingClient} = require('@google-cloud/billing'); const billingClient = new CloudBillingClient({keyFile: jsonKeyFile}); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. const [policy] = await billingClient.getIamPolicy({ resource: billingAccount, }); const role = 'roles/billing.user'; const member = `user:${resellerAdminUser}`; const binding = policy.bindings.find(binding => { return binding.role === role; }); // If the binding already exists, add the user to it, else add a new binding if (binding) { binding.members.push(member); } else { policy.bindings.push({ role, members: [member], }); } // Update the IAM policy await billingClient.setIamPolicy({ resource: billingAccount, policy, }); console.log('=== Set IAM policy'); console.info(policy);
PHP
// Get the name of the customer's billing account from the entitlement $billingAccount = $entitlement->getProvisionedService()->getProvisioningId(); // Create a Cloud Billing API client $billingClient = new Google\Cloud\Billing\V1\CloudBillingClient([ 'credentials' => $JSON_KEY_FILE ]); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. $policy = $billingClient->getIamPolicy($billingAccount /* $resource */); $role = 'roles/billing.user'; $member = 'user:' . $RESELLER_ADMIN_USER; $binding = null; foreach($policy->getBindings() as $b) { if ($b->getRole() == $role) { $binding = $b; break; } } // If the binding already exists, add the user to it, else add a new binding if ($binding) { $binding->getMembers()[] = $member; } else { $binding = new \Google\Cloud\Iam\V1\Binding([ 'role' => $role, 'members' => [ $member ], ]); $policy->getBindings()[] = $binding; } // Update the IAM policy $billingClient->setIamPolicy( $billingAccount /* $resource */, $policy ); print '=== Set IAM policy' . PHP_EOL; print $policy->serializeToJsonString() . PHP_EOL;
Python
# Get the name of the customer's billing account from the entitlement billing_account = entitlement.provisioned_service.provisioning_id # Create a Cloud Billing API client billing_credentials = service_account.Credentials.from_service_account_file( JSON_KEY_FILE) billing_client = billing.CloudBillingClient(credentials=billing_credentials) # For the purpose of this codelab, we'll grant an IAM role to the reseller # admin user, but this is not a requirement for a production integration. policy = billing_client.get_iam_policy(resource=billing_account) role = "roles/billing.user" member = "user:" + RESELLER_ADMIN_USER binding = None for b in policy.bindings: if b.role == role: binding = b break # If the binding already exists, add the user to it, else add a new binding if binding is not None: binding.members.append(member) else: binding = policy_pb2.Binding(role=role, members=[member]) policy.bindings.append(binding) # Update the IAM policy billing_client.set_iam_policy(request={ "resource": billing_account, "policy": policy }) print("=== Set IAM policy") print(policy)
Ruby
# Get the name of the customer's billing account from the entitlement billing_account = entitlement.provisioned_service.provisioning_id # Create a Cloud Billing API client billing_client = Google::Cloud::Billing::cloud_billing_service do |config| config.credentials = JSON_PRIVATE_KEY_FILE end # For the purpose of this codelab, we'll grant an IAM role to the reseller # admin user, but this is not a requirement for a production integration. iam_request = Google::Iam::V1::GetIamPolicyRequest.new do |config| config.billing_account = billing_account end policy = billing_client.get_iam_policy({ resource: billing_account }) role = 'roles/billing.user' member = "user:#{RESELLER_ADMIN_USER}" binding = policy.bindings.detect { |b| b.role == role } # If the binding already exists, add the user to it, else add a new binding if (binding != nil) binding.members.add(member) else binding = Google::Iam::V1::Binding.new binding.role = role binding.members.push(member) policy.bindings.push(binding) end request = Google::Iam::V1::SetIamPolicyRequest.new do |config| config.policy = policy end # Update the IAM policy billing_client.set_iam_policy({ resource: billing_account, policy: policy }) puts('=== Set IAM policy') puts(policy.inspect)
すべてを組み合わせる
Google Cloud(旧 Google Cloud Platform)利用資格を持つ顧客をプロビジョニングするための完全なコード例。
C#
// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Instructions for this codelab can be found on this page // https://cloud.google.com/channel/docs/codelabs/gcp/provisioning using Google.Apis.Auth.OAuth2; using Google.Api.Gax; using Google.Cloud.Billing.V1; // optional using Google.Cloud.Channel.V1; using Google.Cloud.Iam.V1; // optional using Google.Type; using Newtonsoft.Json; using System; using System.Linq; namespace Codelab { class Program { /***************** REPLACE WITH YOUR OWN VALUES ********************************/ private static readonly string jsonKeyFile = "path/to/json_key_file.json"; private static readonly string resellerAdminUser = "admin@yourresellerdomain.com"; private static readonly string accountId = "C012345"; private static readonly string customerDomain = "example.com"; /*******************************************************************************/ private static readonly string accountName = "accounts/" + accountId; private static CloudChannelServiceClient client; static void Main(string[] args) { // Set up credentials with user impersonation ICredential credential = GoogleCredential.FromFile(jsonKeyFile) .CreateScoped(CloudChannelServiceClient.DefaultScopes) .CreateWithUser(resellerAdminUser); // Create the API client client = new CloudChannelServiceClientBuilder { TokenAccessMethod = credential.GetAccessTokenForRequestAsync }.Build(); Offer selectedOffer = SelectOffer(); Customer customer = CreateCustomer(); Entitlement entitlement = CreateEntitlement(customer, selectedOffer); SetIamPolicy(entitlement); } static Offer SelectOffer() { PagedEnumerable<ListOffersResponse, Offer> offers = client.ListOffers(new ListOffersRequest { Parent = accountName }); // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration Offer selectedOffer = offers.FirstOrDefault( o => o.Sku.MarketingInfo.DisplayName == "Google Cloud Platform"); Console.WriteLine("=== Selected offer"); Console.WriteLine(JsonConvert.SerializeObject(selectedOffer)); return selectedOffer; } static Customer CreateCustomer() { // Create the Customer resource CreateCustomerRequest request = new CreateCustomerRequest { Parent = accountName, Customer = new Customer { OrgDisplayName = "Acme Corp", OrgPostalAddress = new PostalAddress { AddressLines = { "1800 Amphibious Blvd" }, PostalCode = "94045", RegionCode = "US" }, Domain = customerDomain, // Optional. Add the CRM ID for this customer. CorrelationId = "CRMID012345" } }; Customer customer = client.CreateCustomer(request); Console.WriteLine("=== Created customer with id " + customer.Name); Console.WriteLine(JsonConvert.SerializeObject(customer)); return customer; } static Entitlement CreateEntitlement(Customer customer, Offer selectedOffer) { // This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" string displayName = "Reseller XYZ - Acme corp"; CreateEntitlementRequest request = new CreateEntitlementRequest { Parent = customer.Name, Entitlement = new Entitlement { Offer = selectedOffer.Name, Parameters = { new Parameter { Name = "display_name", Value = new Value { StringValue = displayName } } }, // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. PurchaseOrderId = "A codelab test" } }; // This call returns a long-running operation. var operation = client.CreateEntitlement(request); // Wait for the long-running operation and get the result. Entitlement entitlement = operation.PollUntilCompleted().Result; Console.WriteLine("=== Created entitlement"); Console.WriteLine(JsonConvert.SerializeObject(entitlement)); return entitlement; } static void SetIamPolicy(Entitlement entitlement) { // Get the name of the customer's billing account from the entitlement String billingAccount = entitlement.ProvisionedService.ProvisioningId; // Create a Cloud Billing API client CloudBillingClient billingClient = new CloudBillingClientBuilder { CredentialsPath = jsonKeyFile }.Build(); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. Policy policy = billingClient.GetIamPolicy(billingAccount); string role = "roles/billing.user"; string member = "user:" + resellerAdminUser; var binding = policy.Bindings.FirstOrDefault(b => b.Role == role); // If the binding already exists, add the user to it, else add a new binding if (binding != null) { binding.Members.Add(member); } else { binding = new Binding { Role = role }; binding.Members.Add(member); policy.Bindings.Add(binding); } // Update the IAM policy SetIamPolicyRequest request = new SetIamPolicyRequest { Resource = billingAccount, Policy = policy }; billingClient.SetIamPolicy(request); Console.WriteLine("=== Set IAM policy"); Console.WriteLine(JsonConvert.SerializeObject(policy)); } } }
Go
// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Instructions for this codelab can be found on this page // https://cloud.google.com/channel/docs/codelabs/gcp/provisioning package main import ( "context" "fmt" "io/ioutil" billing "cloud.google.com/go/billing/apiv1" // optional channel "cloud.google.com/go/channel/apiv1" "golang.org/x/oauth2/google" "google.golang.org/api/iterator" "google.golang.org/api/option" channelpb "google.golang.org/genproto/googleapis/cloud/channel/v1" iampb "google.golang.org/genproto/googleapis/iam/v1" // optional "google.golang.org/genproto/googleapis/type/postaladdress" "google.golang.org/protobuf/encoding/protojson" ) // ############## REPLACE WITH YOUR OWN VALUES #################### const jsonKeyFile = "path/to/json_key_file.json" const resellerAdminUser = "admin@yourresellerdomain.com" const accountID = "C012345" const customerDomain = "example.com" // ################################################################ const accountName = "accounts/" + accountID func main() { ctx := context.Background() // set up credentials with user impersonation jsonKey, _ := ioutil.ReadFile(jsonKeyFile) jwt, _ := google.JWTConfigFromJSON(jsonKey, "https://www.googleapis.com/auth/apps.order") jwt.Subject = resellerAdminUser tokenSource := jwt.TokenSource(ctx) // create the API client client, _ := channel.NewCloudChannelClient(ctx, option.WithTokenSource(tokenSource)) selectedOffer := selectOffer(ctx, client) customer := createCustomer(ctx, client) entitlement := createEntitlement(ctx, client, customer, selectedOffer) setIamPolicy(ctx, entitlement) } func selectOffer(ctx context.Context, client *channel.CloudChannelClient) *channelpb.Offer { var selectedOffer *channelpb.Offer req := &channelpb.ListOffersRequest{ Parent: accountName, } it := client.ListOffers(ctx, req) // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another and // is not a recommended model for your production integration. for { offer, err := it.Next() if err == iterator.Done { break } if offer.Sku.MarketingInfo.DisplayName == "Google Cloud Platform" { selectedOffer = offer break } } fmt.Println("=== Selected offer") fmt.Println(protojson.Format(selectedOffer)) return selectedOffer } func createCustomer(ctx context.Context, client *channel.CloudChannelClient) *channelpb.Customer { // Create the Customer resource req := &channelpb.CreateCustomerRequest{ Parent: accountName, Customer: &channelpb.Customer{ OrgDisplayName: "Acme Corp", OrgPostalAddress: &postaladdress.PostalAddress{ AddressLines: []string{"1800 Amphibious Blvd"}, PostalCode: "94045", RegionCode: "US", }, Domain: customerDomain, // Optional. Add the CRM ID for this customer. CorrelationId: "CRMID012345", // Distributors need to pass the following value // ChannelPartnerId: channelPartnerLinkId }, } customer, _ := client.CreateCustomer(ctx, req) fmt.Println("=== Created customer with id " + customer.Name) fmt.Println(protojson.Format(customer)) return customer } func createEntitlement(ctx context.Context, client *channel.CloudChannelClient, customer *channelpb.Customer, selectedOffer *channelpb.Offer) *channelpb.Entitlement { // This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" const displayName = "Reseller XYZ - Acme corp" // This endpoint returns a long-running operation. req := &channelpb.CreateEntitlementRequest{ Parent: customer.Name, Entitlement: &channelpb.Entitlement{ Offer: selectedOffer.Name, Parameters: []*channelpb.Parameter{ { Name: "display_name", Value: &channelpb.Value{ Kind: &channelpb.Value_StringValue{StringValue: displayName}, }, }, }, // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. PurchaseOrderId: "A codelab test", }, } // This endpoint returns a long-running operation. op, _ := client.CreateEntitlement(ctx, req) // Wait for the long-running operation and get the result. entitlement, _ := op.Wait(ctx) fmt.Println("=== Created entitlement") fmt.Println(protojson.Format(entitlement)) return entitlement } func setIamPolicy(ctx context.Context, entitlement *channelpb.Entitlement) { // Get the name of the customer's billing account from the entitlement billingAccount := entitlement.ProvisionedService.ProvisioningId // Create a Cloud Billing API client client, _ := billing.NewCloudBillingClient(ctx, option.WithCredentialsFile(jsonKeyFile)) // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. getPolicyReq := &iampb.GetIamPolicyRequest{Resource: billingAccount} policy, _ := client.GetIamPolicy(ctx, getPolicyReq) var binding *iampb.Binding const role = "roles/billing.user" const member = "user:" + resellerAdminUser for _, b := range policy.Bindings { if b.Role == role { binding = b break } } // If the binding already exists, add the user to it, else add a new binding if binding != nil { binding.Members = append(binding.Members, member) } else { binding = &iampb.Binding{ Role: role, Members: []string{member}, } policy.Bindings = append(policy.Bindings, binding) } // Update the IAM policy setPolicyReq := &iampb.SetIamPolicyRequest{ Resource: billingAccount, Policy: policy, } client.SetIamPolicy(ctx, setPolicyReq) fmt.Println("=== Set IAM policy") fmt.Println(protojson.Format(policy)) }
Java
// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Instructions for this codelab can be found on this page // https://cloud.google.com/channel/docs/codelabs/gcp/provisioning import com.google.api.gax.core.FixedCredentialsProvider; import com.google.api.gax.longrunning.OperationFuture; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.channel.v1.CloudChannelServiceClient; import com.google.cloud.channel.v1.CloudChannelServiceSettings; import com.google.cloud.channel.v1.CreateCustomerRequest; import com.google.cloud.channel.v1.CreateEntitlementRequest; import com.google.cloud.channel.v1.Customer; import com.google.cloud.channel.v1.Entitlement; import com.google.cloud.channel.v1.ListOffersRequest; import com.google.cloud.channel.v1.Offer; import com.google.cloud.channel.v1.OperationMetadata; import com.google.cloud.channel.v1.Parameter; import com.google.cloud.channel.v1.Value; import com.google.gson.Gson; import com.google.type.PostalAddress; import java.io.FileInputStream; import java.io.IOException; import java.util.Iterator; import java.util.concurrent.ExecutionException; // optional import java.util.ArrayList; import java.util.List; import com.google.cloud.billing.v1.CloudBillingClient; import com.google.cloud.billing.v1.CloudBillingSettings; import com.google.iam.v1.Binding; import com.google.iam.v1.Policy; /** * This is a basic example of provisioning a GCP customer. */ public class Codelab { /***************** REPLACE WITH YOUR OWN VALUES ********************************/ public static final String JSON_KEY_FILE = "path/to/json_key_file.json"; public static final String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com"; public static final String ACCOUNT_ID = "C012345"; public static final String CUSTOMER_DOMAIN = "example.com"; /*******************************************************************************/ public static final String ACCOUNT_NAME = "accounts/" + ACCOUNT_ID; private static CloudChannelServiceClient client; private static final Gson gson = new Gson(); public static void main(String[] args) throws IOException, ExecutionException, InterruptedException { // Set up credentials with user impersonation FileInputStream jsonKeyFileSteam = new FileInputStream(JSON_KEY_FILE); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(jsonKeyFileSteam) .createScoped("https://www.googleapis.com/auth/apps.order") .createDelegated(RESELLER_ADMIN_USER); CloudChannelServiceSettings clientSettings = CloudChannelServiceSettings.newBuilder() .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); // Create the API client client = CloudChannelServiceClient.create(clientSettings); Offer selectedOffer = selectOffer(); Customer customer = createCustomer(); Entitlement entitlement = createEntitlement(customer, selectedOffer); setIamPolicy(entitlement); } private static Offer selectOffer() { ListOffersRequest request = ListOffersRequest.newBuilder().setParent(ACCOUNT_NAME).build(); // For the purpose of this codelab, the code lists all offers and selects // the first offer for Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration CloudChannelServiceClient.ListOffersPagedResponse response = client.listOffers(request); Offer selectedOffer = Offer.newBuilder().build(); Iterator<Offer> iterator = response.iterateAll().iterator(); while (iterator.hasNext()) { Offer offer = iterator.next(); String skuName = offer.getSku().getMarketingInfo().getDisplayName(); if (skuName.equals("Google Cloud Platform")) { selectedOffer = offer; break; } } System.out.println("=== Selected offer"); System.out.println(gson.toJson(selectedOffer)); return selectedOffer; } private static Customer createCustomer() throws InterruptedException, ExecutionException { // Create the Customer resource PostalAddress postalAddress = PostalAddress.newBuilder() .addAddressLines("1800 Amphibious Blvd") .setPostalCode("94045") .setRegionCode("US") .build(); CreateCustomerRequest request = CreateCustomerRequest.newBuilder() .setParent(ACCOUNT_NAME) .setCustomer( Customer.newBuilder() .setOrgDisplayName("Acme Corp") .setOrgPostalAddress(postalAddress) .setDomain(CUSTOMER_DOMAIN) // Optional. Add the CRM ID for this customer. .setCorrelationId("CRMID012345") // Distributors need to pass the following field // .setChannelPartnerId(channelPartnerLinkId) .build()) .build(); Customer customer = client.createCustomer(request); System.out.println("=== Created customer with id " + customer.getName()); System.out.println(gson.toJson(customer)); return customer; } private static Entitlement createEntitlement(Customer customer, Offer selectedOffer) throws InterruptedException, ExecutionException { // This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" String displayName = "Reseller XYZ - Acme corp"; Entitlement entitlement = Entitlement.newBuilder() .setOffer(selectedOffer.getName()) .addParameters( Parameter.newBuilder() .setName("display_name") .setValue(Value.newBuilder().setStringValue(displayName).build()) .build()) // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. .setPurchaseOrderId("A codelab test") .build(); CreateEntitlementRequest request = CreateEntitlementRequest.newBuilder() .setParent(customer.getName()) .setEntitlement(entitlement) .build(); // This call returns a long-running operation. OperationFuture<Entitlement, OperationMetadata> operation = client.createEntitlementAsync(request); // Wait for the long-running operation and get the result. entitlement = operation.get(); System.out.println("=== Created entitlement"); System.out.println(gson.toJson(entitlement)); return entitlement; } private static void setIamPolicy(Entitlement entitlement) throws IOException { // Get the name of the customer's billing account from the entitlement String billingAccount = entitlement.getProvisionedService().getProvisioningId(); // Create a Cloud Billing API client FileInputStream jsonKeyFileSteam = new FileInputStream(JSON_KEY_FILE); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(jsonKeyFileSteam); CloudBillingSettings clientSettings = CloudBillingSettings.newBuilder() .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); CloudBillingClient client = CloudBillingClient.create(clientSettings); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. Policy policy = client.getIamPolicy(billingAccount); Binding binding = null; int bindingIndex = 0; String role = "roles/billing.user"; String member = "user:" + RESELLER_ADMIN_USER; // getBindingsList() returns an ImmutableList and copying over to an ArrayList so it's mutable. List<Binding> bindings = new ArrayList(policy.getBindingsList()); for (int index = 0; index < bindings.size(); index++) { Binding b = bindings.get(index); if (b.getRole().equals(role)) { binding = b; bindingIndex = index; break; } } // If the binding already exists, add the user to it, else add a new binding Policy.Builder newPolicyBuilder = policy.toBuilder(); if (binding != null) { newPolicyBuilder.setBindings(bindingIndex, binding.toBuilder().addMembers(member).build()); } else { binding = Binding.newBuilder() .setRole(role) .addMembers(member) .build(); newPolicyBuilder.addBindings(binding); } // Update the IAM policy Policy newPolicy = newPolicyBuilder.build(); client.setIamPolicy(billingAccount, newPolicy); System.out.println("=== Set IAM policy"); System.out.println(gson.toJson(newPolicy)); } }
Node.js
// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Instructions for this codelab can be found on this page // https://cloud.google.com/channel/docs/codelabs/gcp/provisioning const {JWT} = require('google-auth-library'); const {grpc} = require('google-gax'); const {CloudChannelServiceClient} = require('@google-cloud/channel'); // ############## REPLACE WITH YOUR OWN VALUES #################### const jsonKeyFile = 'path/to/json_key_file.json'; const resellerAdminUser = 'admin@yourresellerdomain.com'; const accountId = 'C012345'; const customerDomain = 'example.com'; // ################################################################ const accountName = `accounts/${accountId}`; // Set up credentials with user impersonation const authClient = new JWT({ keyFile: jsonKeyFile, scopes: ['https://www.googleapis.com/auth/apps.order'], subject: resellerAdminUser, }); const sslCreds = grpc.credentials.combineChannelCredentials( grpc.credentials.createSsl(), grpc.credentials.createFromGoogleCredential(authClient) ); // Create the API client const client = new CloudChannelServiceClient({sslCreds}); async function main() { const selectedOffer = await selectOffer(); const customer = await createCustomer(); const entitlement = await createEntitlement(customer, selectedOffer); await setIamPolicy(entitlement); } async function selectOffer() { const [offers] = await client.listOffers({ parent: accountName, }); // For the purpose of this codelab, the code lists all offers and selects // the first offer for the Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration const selectedOffer = offers.find(o => { return o.sku.marketingInfo.displayName === 'Google Cloud Platform'; }); console.log('=== Selected offer'); console.info(selectedOffer); return selectedOffer; } async function createCustomer() { // Create the Customer resource const [customer] = await client.createCustomer({ parent: accountName, customer: { orgDisplayName: 'Acme Corp', orgPostalAddress: { addressLines: ['1800 Amphibious Blvd'], postalCode: '94045', regionCode: 'US', }, domain: customerDomain, // Optional. Add the CRM ID for this customer. correlationId: "CRMID012345", // Distributors need to pass the following field // channelPartnerId: channelPartnerLinkId }, }); console.log(`=== Created customer with id ${customer.name}`); console.info(customer); return customer; } async function createEntitlement(customer, selectedOffer) { // This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" const displayName = 'Reseller XYZ - Acme corp'; // This call returns a long-running operation. const [operation] = await client.createEntitlement({ parent: customer.name, entitlement: { offer: selectedOffer.name, parameters: [ { name: 'display_name', value: { stringValue: displayName, }, }, ], // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. purchaseOrderId: 'A codelab test', }, }); // Wait for the long-running operation and get the result. const [entitlement] = await operation.promise(); console.log('=== Created entitlement'); console.info(entitlement); return entitlement; } async function setIamPolicy(entitlement) { // Get the name of the customer's billing account from the entitlement const billingAccount = entitlement.provisionedService.provisioningId; // Create a Cloud Billing API client const {CloudBillingClient} = require('@google-cloud/billing'); const billingClient = new CloudBillingClient({keyFile: jsonKeyFile}); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. const [policy] = await billingClient.getIamPolicy({ resource: billingAccount, }); const role = 'roles/billing.user'; const member = `user:${resellerAdminUser}`; const binding = policy.bindings.find(binding => { return binding.role === role; }); // If the binding already exists, add the user to it, else add a new binding if (binding) { binding.members.push(member); } else { policy.bindings.push({ role, members: [member], }); } // Update the IAM policy await billingClient.setIamPolicy({ resource: billingAccount, policy, }); console.log('=== Set IAM policy'); console.info(policy); } main().catch(err => { console.error(err.message); process.exitCode = 1; }); process.on('unhandledRejection', err => { console.error(err.message); process.exitCode = 1; });
PHP
<?php // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Instructions for this codelab can be found on this page // https://cloud.google.com/channel/docs/codelabs/gcp/provisioning require 'vendor/autoload.php'; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Cloud\Channel; // ############## REPLACE WITH YOUR OWN VALUES #################### $JSON_KEY_FILE = 'path/to/json_key_file.json'; $RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'; $ACCOUNT_ID = 'C012345'; $CUSTOMER_DOMAIN = 'example.com'; // ################################################################ $ACCOUNT_NAME = 'accounts/' . $ACCOUNT_ID; // Set up credentials with user impersonation $credentials = new ServiceAccountCredentials( 'https://www.googleapis.com/auth/apps.order', /* $scope */ $JSON_KEY_FILE, /* $keyFile */ $RESELLER_ADMIN_USER /* $sub */ ); // Create the API client $client = new Channel\V1\CloudChannelServiceClient([ 'credentials' => $credentials ]); $selectedOffer = selectOffer(); $customer = createCustomer(); $entitlement = createEntitlement($customer, $selectedOffer); setIamPolicy($entitlement); function selectOffer() { global $client, $ACCOUNT_NAME; $offers = $client->listOffers($ACCOUNT_NAME /* parent */); // For the purpose of this codelab, the code lists all offers and selects // the first offer for the Google Cloud Platform. // This is needed because offerIds vary from one account to another, // but this is not a recommended model for your production integration $sampleSku = 'Google Cloud Platform'; foreach ($offers as $offer) { if ($offer->getSku()->getMarketingInfo()->getDisplayName() == $sampleSku) { $selectedOffer = $offer; break; } } print '=== Selected offer' . PHP_EOL; print $selectedOffer->serializeToJsonString() . PHP_EOL; return $selectedOffer; } function createCustomer() { global $client, $ACCOUNT_NAME, $CUSTOMER_DOMAIN; // Create the Customer resource $customer = $client->createCustomer( $ACCOUNT_NAME /* parent */, new Channel\V1\Customer([ 'org_display_name' => 'Acme Corp', 'org_postal_address' => new Google\Type\PostalAddress([ 'address_lines' => ['1800 Amphibious Blvd'], 'postal_code' => '94045', 'region_code' => 'US', ]), 'domain' => $CUSTOMER_DOMAIN, // Optional. Add the CRM ID for this customer. 'correlation_id' => 'CRMID012345', // Distributors need to pass the following field // 'channel_partner_id' => $channelPartnerLinkId ]) ); print '=== Created customer with id ' . $customer->getName() . PHP_EOL; print $customer->serializeToJsonString() . PHP_EOL; return $customer; } function createEntitlement($customer, $selectedOffer) { global $client; // This display name shows on the Google Cloud console when a customer // links the account to their project. // Recommended format: "[Reseller name] - [Customer name]" $displayName = 'Reseller XYZ - Acme corp'; // This call returns a long-running operation. $operation = $client->createEntitlement( $customer->getName() /* parent */, new Channel\V1\Entitlement([ 'offer' => $selectedOffer->getName(), 'parameters' => [ new Channel\V1\Parameter([ 'name' => 'display_name', 'value' => new Channel\V1\Value([ 'string_value' => $displayName, ]) ]), ], // A string of up to 80 characters. // We recommend using an internal transaction ID or // identifier for the customer in this field. 'purchase_order_id' => 'A codelab test' ]) ); // Wait for the long-running operation and get the result. $operation->pollUntilComplete(); $entitlement = $operation->getResult(); print '=== Created entitlement' . PHP_EOL; print $entitlement->serializeToJsonString() . PHP_EOL; return $entitlement; } function setIamPolicy($entitlement) { global $JSON_KEY_FILE, $RESELLER_ADMIN_USER; // Get the name of the customer's billing account from the entitlement $billingAccount = $entitlement->getProvisionedService()->getProvisioningId(); // Create a Cloud Billing API client $billingClient = new Google\Cloud\Billing\V1\CloudBillingClient([ 'credentials' => $JSON_KEY_FILE ]); // For the purpose of this codelab, we'll grant an IAM role to the reseller // admin user, but this is not a requirement for a production integration. $policy = $billingClient->getIamPolicy($billingAccount /* $resource */); $role = 'roles/billing.user'; $member = 'user:' . $RESELLER_ADMIN_USER; $binding = null; foreach($policy->getBindings() as $b) { if ($b->getRole() == $role) { $binding = $b; break; } } // If the binding already exists, add the user to it, else add a new binding if ($binding) { $binding->getMembers()[] = $member; } else { $binding = new \Google\Cloud\Iam\V1\Binding([ 'role' => $role, 'members' => [ $member ], ]); $policy->getBindings()[] = $binding; } // Update the IAM policy $billingClient->setIamPolicy( $billingAccount /* $resource */, $policy ); print '=== Set IAM policy' . PHP_EOL; print $policy->serializeToJsonString() . PHP_EOL; }
Python
# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # """GCP Provisioning codelab. Instructions for this codelab can be found on this page: https://cloud.google.com/channel/docs/codelabs/gcp/provisioning """ from google.cloud import channel from google.oauth2 import service_account # optional from google.cloud import billing from google.iam.v1 import policy_pb2 ############## REPLACE WITH YOUR OWN VALUES #################### JSON_KEY_FILE = "path/to/json_key_file.json" RESELLER_ADMIN_USER = "admin@yourresellerdomain.com" ACCOUNT_ID = "C012345" CUSTOMER_DOMAIN = "example.com" ################################################################ ACCOUNT_NAME = "accounts/" + ACCOUNT_ID # Set up credentials with user impersonation credentials = service_account.Credentials.from_service_account_file( JSON_KEY_FILE, scopes=["https://www.googleapis.com/auth/apps.order"]) credentials_delegated = credentials.with_subject(RESELLER_ADMIN_USER) # Create the API client client = channel.CloudChannelServiceClient(credentials=credentials_delegated) def main(): offer = select_offer() customer = create_customer() entitlement = create_entitlement(customer, offer) set_iam_policy(entitlement) def select_offer(): """Selects a GCP offer. Returns: A Channel API Offer for GCP """ request = channel.ListOffersRequest(parent=ACCOUNT_NAME) offers = client.list_offers(request) # For the purpose of this codelab, the code lists all offers and selects # the first offer for Google Cloud Platform. # This is needed because offerIds vary from one account to another, # but this is not a recommended model for your production integration selected_offer = None for offer in offers: if offer.sku.marketing_info.display_name == "Google Cloud Platform": selected_offer = offer break print("=== Selected offer") print(selected_offer) return selected_offer def create_customer(): """Create the Customer resource, with a cloud identity. Returns: The created Channel API Customer """ # Create the Customer resource request = channel.CreateCustomerRequest( parent=ACCOUNT_NAME, customer={ "org_display_name": "Acme Corp", "domain": CUSTOMER_DOMAIN, "org_postal_address": { "address_lines": ["1800 Amphibious Blvd"], "postal_code": "94045", "region_code": "US" }, # Optional. Add the CRM ID for this customer. "correlation_id": "CRMID012345" }) # Distributors need to also pass the following field for the `customer` # "channel_partner_id": channel_partner_link_id customer = client.create_customer(request) print("=== Created customer with id ", customer.name) print(customer) return customer def create_entitlement(customer, selected_offer): """Create the Entitlement. Args: customer: a Customer resource selected_offer: an Offer Returns: The created Channel API Entitlement """ # This display name shows on the Google Cloud console when a customer # links the account to their project. # Recommended format: "[Reseller name] - [Customer name]" display_name = "Reseller XYZ - Acme corp" request = channel.CreateEntitlementRequest( parent=customer.name, entitlement={ "offer": selected_offer.name, "parameters": [{ "name": "display_name", "value": { "string_value": display_name } }], # A string of up to 80 characters. # We recommend an internal transaction ID or # identifier for this customer in this field. "purchase_order_id": "A codelab test" }) # This call returns a long-running operation. operation = client.create_entitlement(request) # Wait for the long-running operation and get the result. entitlement = operation.result() print("=== Created entitlement") print(entitlement) return entitlement def set_iam_policy(entitlement): """Sets IAM Policy on the created entitlement. Args: entitlement: a GCP Entitlement """ # Get the name of the customer's billing account from the entitlement billing_account = entitlement.provisioned_service.provisioning_id # Create a Cloud Billing API client billing_credentials = service_account.Credentials.from_service_account_file( JSON_KEY_FILE) billing_client = billing.CloudBillingClient(credentials=billing_credentials) # For the purpose of this codelab, we'll grant an IAM role to the reseller # admin user, but this is not a requirement for a production integration. policy = billing_client.get_iam_policy(resource=billing_account) role = "roles/billing.user" member = "user:" + RESELLER_ADMIN_USER binding = None for b in policy.bindings: if b.role == role: binding = b break # If the binding already exists, add the user to it, else add a new binding if binding is not None: binding.members.append(member) else: binding = policy_pb2.Binding(role=role, members=[member]) policy.bindings.append(binding) # Update the IAM policy billing_client.set_iam_policy(request={ "resource": billing_account, "policy": policy }) print("=== Set IAM policy") print(policy) if __name__ == "__main__": main()
Ruby
# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # GCP Provisioning codelab. # Instructions for this codelab can be found on this page: # https://cloud.google.com/channel/docs/codelabs/gcp/provisioning require 'google-cloud-channel' require 'google-cloud-billing' # Optional require 'google/iam/v1/policy_pb' # Optional ################## REPLACE WITH YOUR OWN VALUES ################################ JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json' RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com' ACCOUNT_ID = 'C012345' CUSTOMER_DOMAIN = 'example.com' ################################################################################ ACCOUNT_NAME = "accounts/#{ACCOUNT_ID}" # Set up credentials with user impersonation credentials = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: File.open(JSON_PRIVATE_KEY_FILE), scope: 'https://www.googleapis.com/auth/apps.order') credentials.sub = RESELLER_ADMIN_USER # Create the API client CLIENT = Google::Cloud::Channel::cloud_channel_service do |config| config.credentials = credentials end def main offer = select_offer customer = create_customer entitlement = create_entitlement(customer, offer) set_iam_policy(entitlement) end def select_offer # For the purpose of this codelab, the code lists all offers and selects # the first offer for Google Cloud Platform. # This is needed because offerIds vary from one account to another, # but this is not a recommended model for your production integration request = Google::Cloud::Channel::V1::ListOffersRequest.new({ parent: ACCOUNT_NAME }) offers = CLIENT.list_offers(request) sample_offer = 'Google Cloud Platform' offer = offers.detect { |offer| offer.sku.marketing_info.display_name == sample_offer } puts('=== Selected offer') puts(offer.inspect) offer end def create_customer # Create the Customer resource request = Google::Cloud::Channel::V1::CreateCustomerRequest.new( parent: ACCOUNT_NAME, customer: { 'org_display_name': 'Acme Corp', 'domain': CUSTOMER_DOMAIN, 'org_postal_address': { 'address_lines': ['1800 Amphibious Blvd'], 'postal_code': '94045', 'region_code': 'US' }, # Optional. Add the CRM ID for this customer. 'correlation_id': 'CRMID012345' }) # Distributors need to also pass the following field for the `customer` # "channel_partner_id": channel_partner_link_id customer = CLIENT.create_customer(request) puts("=== Created customer with id " + customer.name) puts(customer.inspect) customer end def create_entitlement(customer, selected_offer) # This display name shows on the Google Cloud console when a customer # links the account to their project. # Recommended format: "[Reseller name] - [Customer name]" display_name = 'Reseller XYZ - Acme Corp' request = Google::Cloud::Channel::V1::CreateEntitlementRequest.new( parent: customer.name, entitlement: { offer: selected_offer.name, # Setting 5 seats for this Annual offer parameters: [{ name: 'display_name', value: { string_value: display_name } }], # A string of up to 80 characters. # We recommend an internal transaction ID or # identifier for this customer in this field. purchase_order_id: 'A codelab test' }) # This call returns a long-running operation. operation = CLIENT.create_entitlement(request) # Wait for the long-running operation and get the result. CLIENT.operations_client.wait_operation(Google::Longrunning::WaitOperationRequest .new({ name: operation.name })) operation = CLIENT.operations_client.get_operation(Google::Longrunning::GetOperationRequest .new({ name: operation.name })) entitlement = operation.response puts("=== Created entitlement") puts(entitlement) entitlement end def set_iam_policy(entitlement) # Get the name of the customer's billing account from the entitlement billing_account = entitlement.provisioned_service.provisioning_id # Create a Cloud Billing API client billing_client = Google::Cloud::Billing::cloud_billing_service do |config| config.credentials = JSON_PRIVATE_KEY_FILE end # For the purpose of this codelab, we'll grant an IAM role to the reseller # admin user, but this is not a requirement for a production integration. iam_request = Google::Iam::V1::GetIamPolicyRequest.new do |config| config.billing_account = billing_account end policy = billing_client.get_iam_policy({ resource: billing_account }) role = 'roles/billing.user' member = "user:#{RESELLER_ADMIN_USER}" binding = policy.bindings.detect { |b| b.role == role } # If the binding already exists, add the user to it, else add a new binding if (binding != nil) binding.members.add(member) else binding = Google::Iam::V1::Binding.new binding.role = role binding.members.push(member) policy.bindings.push(binding) end request = Google::Iam::V1::SetIamPolicyRequest.new do |config| config.policy = policy end # Update the IAM policy billing_client.set_iam_policy({ resource: billing_account, policy: policy }) puts('=== Set IAM policy') puts(policy.inspect) end main()