1+ // https://github.com/GoogleCloudPlatform/functions-framework-python
2+ // https://github.com/GoogleCloudPlatform/functions-framework-nodejs
3+
4+ // Simplified representation of `stop_billing` logic
5+ const { CloudBillingClient} = require ( '@google-cloud/billing' ) ;
6+ const functions = require ( '@google-cloud/functions-framework' ) ;
7+ const gcpMetadata = require ( 'gcp-metadata' ) ;
8+
9+ const billing = new CloudBillingClient ( ) ;
10+
11+ const PROJECT_ID = process . env . GOOGLE_CLOUD_PROJECT ;
12+
13+ /*
14+ functions.cloudEvent('StopBillingCloudEvent', async (cloudEvent) => {
15+ // console.log(cloudEvent);
16+ const eventData = Buffer.from(
17+ cloudEvent.data['message']['data'],
18+ 'base64'
19+ ).toString();
20+
21+ const eventObject = JSON.parse(eventData);
22+
23+ console.log(
24+ `Cost: ${eventObject.costAmount} Budget: ${eventObject.budgetAmount}`
25+ );
26+
27+ console.log("Getting billing info for project...");
28+ console.log("Disabling billing for project...");
29+ console.log("Billing disabled. (Simulated)");
30+ });
31+ */
32+
33+ functions . cloudEvent ( 'StopBillingCloudEvent' , async cloudEvent => {
34+ // TODO(developer): As stopping billing is a destructive action
35+ // for your project, change the following constant to false
36+ // after you validate with a test budget.
37+ const simulateDeactivation = true ;
38+
39+ let projectId = PROJECT_ID ;
40+
41+ if ( projectId === undefined ) {
42+ try {
43+ projectId = await gcpMetadata . project ( 'project-id' ) ;
44+ } catch ( error ) {
45+ console . error ( 'project-id metadata not found:' , error ) ;
46+ return ;
47+ }
48+ }
49+
50+ const projectName = `projects/${ projectId } ` ;
51+
52+ const eventData = Buffer . from (
53+ cloudEvent . data [ 'message' ] [ 'data' ] ,
54+ 'base64'
55+ ) . toString ( ) ;
56+
57+ const eventObject = JSON . parse ( eventData ) ;
58+
59+ console . log (
60+ `Cost: ${ eventObject . costAmount } Budget: ${ eventObject . budgetAmount } `
61+ ) ;
62+
63+ if ( eventObject . costAmount <= eventObject . budgetAmount ) {
64+ console . log ( 'No action required. Current cost is within budget.' ) ;
65+ return ;
66+ }
67+
68+ console . log ( `Disabling billing for project '${ projectName } '...` ) ;
69+
70+ const billingEnabled = await _isBillingEnabled ( projectName ) ;
71+ if ( billingEnabled ) {
72+ _disableBillingForProject ( projectName , simulateDeactivation ) ;
73+ } else {
74+ console . log ( 'Billing is already disabled.' ) ;
75+ }
76+ } ) ;
77+
78+ /**
79+ * Determine whether billing is enabled for a project
80+ * @param {string } projectName The name of the project to check
81+ * @returns {boolean } Whether the project has billing enabled or not
82+ */
83+ const _isBillingEnabled = async projectName => {
84+ try {
85+ console . log ( `Getting billing info for project '${ projectName } '...` ) ;
86+ const [ res ] = await billing . getProjectBillingInfo ( { name : projectName } ) ;
87+
88+ return res . billingEnabled ;
89+ } catch ( e ) {
90+ console . log ( 'Error getting billing info:' , e ) ;
91+ console . log (
92+ 'Unable to determine if billing is enabled on specified project, ' +
93+ 'assuming billing is enabled'
94+ ) ;
95+
96+ return true ;
97+ }
98+ } ;
99+
100+ /**
101+ * Disable billing for a project by removing its billing account
102+ * @param {string } projectName The name of the project to disable billing
103+ * @param {boolean } simulateDeactivation
104+ * If true, it won't actually disable billing.
105+ * Useful to validate with test budgets.
106+ * @returns {void }
107+ */
108+ const _disableBillingForProject = async ( projectName , simulateDeactivation ) => {
109+ if ( simulateDeactivation ) {
110+ console . log ( 'Billing disabled. (Simulated)' ) ;
111+ return ;
112+ }
113+
114+ // Find more information about `projects/updateBillingInfo` API method here:
115+ // https://cloud.google.com/billing/docs/reference/rest/v1/projects/updateBillingInfo
116+ try {
117+ // To disable billing set the `billingAccountName` field to empty
118+ const requestBody = { billingAccountName : '' } ;
119+
120+ const [ response ] = await billing . updateProjectBillingInfo ( {
121+ name : projectName ,
122+ resource : requestBody ,
123+ } ) ;
124+
125+ console . log ( `Billing disabled: ${ JSON . stringify ( response ) } ` ) ;
126+ } catch ( e ) {
127+ console . log ( 'Failed to disable billing, check permissions.' , e ) ;
128+ }
129+ } ;
0 commit comments