시작하기 전에
Google Cloud 프로젝트를 설정하고 Cloud Channel API를 호출하는 서비스 계정을 만들려면 API 설정 Codelab을 완료해야 합니다.
채널 서비스 작업 자세히 알아보기
개요
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
자바
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))
자바
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))
자바
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))
자바
// 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))
자바
// 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 역할을 부여합니다.
결제 계정 관리자(
roles/billing.admin
) 역할 부여는 이 Codelab의 목적에 부합하는 옵션이지만 프로덕션 통합에서 보다 세분화된 권한을 사용해 볼 수 있습니다. 액세스 권한 부여에 관한 자세한 내용은 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
자바
설치 방법에 관한 안내는 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))
자바
// 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)) }
자바
// 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()