@google-cloud/cloud-run-mcp 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc.json +9 -0
- package/.github/workflows/lint-checker.yml +17 -0
- package/.github/workflows/npm-publish.yml +1 -1
- package/.kokoro/kokoro_build.sh +22 -0
- package/.kokoro/presubmit.cfg +21 -0
- package/.kokoro/run_tests.sh +31 -0
- package/CONTRIBUTING.md +24 -9
- package/README.md +52 -11
- package/REVIEWING.md +20 -0
- package/gemini-extension/GEMINI.md +1 -1
- package/lib/cloud-api/billing.js +183 -0
- package/lib/cloud-api/build.js +200 -0
- package/lib/{gcp-api-helpers.js → cloud-api/helpers.js} +81 -35
- package/lib/{gcp-projects.js → cloud-api/projects.js} +58 -28
- package/lib/cloud-api/registry.js +98 -0
- package/lib/{cloud-run-services.js → cloud-api/run.js} +103 -21
- package/lib/cloud-api/storage.js +123 -0
- package/lib/deployment/constants.js +54 -0
- package/lib/deployment/deployer.js +621 -0
- package/lib/deployment/helpers.js +194 -0
- package/lib/deployment/source-processor.js +124 -0
- package/lib/util/archive.js +104 -0
- package/lib/util/helpers.js +42 -0
- package/mcp-server.js +21 -10
- package/package.json +8 -5
- package/test/local/cloud-api/build.test.js +436 -0
- package/test/local/cloud-api/projects.test.js +18 -0
- package/test/local/deployment-helpers.test.js +231 -0
- package/test/local/mcp-server-stdio.test.js +59 -0
- package/test/local/mcp-server-streamable-http.test.js +61 -0
- package/test/local/notifications.test.js +9 -6
- package/test/local/source-processor.test.js +290 -0
- package/test/local/test-utils.js +51 -0
- package/test/local/tools.test.js +114 -70
- package/test/need-gcp/cloud-run-services.test.js +44 -44
- package/test/need-gcp/{cloud-run-deploy.test.js → deployer.test.js} +3 -56
- package/test/need-gcp/gcp-auth-check.test.js +1 -1
- package/test/need-gcp/gcp-projects.test.js +3 -15
- package/test/need-gcp/test-helpers.js +175 -0
- package/test/need-gcp/workflows/deployment-workflows.test.js +100 -0
- package/tools/register-tools.js +106 -97
- package/tools/tools.js +2 -9
- package/lib/cloud-run-deploy.js +0 -937
- package/lib/gcp-billing-accounts.js +0 -98
- /package/lib/{gcp-auth-check.js → cloud-api/auth.js} +0 -0
- /package/lib/{gcp-metadata.js → cloud-api/metadata.js} +0 -0
package/.c8rc.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Run Lint Checker
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint-check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
with:
|
|
15
|
+
node-version: 20
|
|
16
|
+
- run: npm ci
|
|
17
|
+
- run: npm run lint:check
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 Google LLC
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
# Code under repo is checked out to ${KOKORO_ARTIFACTS_DIR}/git.
|
|
18
|
+
# The final directory name in this path is determined by the scm name specified
|
|
19
|
+
# in the job configuration.
|
|
20
|
+
|
|
21
|
+
cd "${KOKORO_ARTIFACTS_DIR}/github/cloud-run-mcp"
|
|
22
|
+
.kokoro/run_tests.sh
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- protobuffer -*-
|
|
2
|
+
# proto-file: google3/devtools/kokoro/config/proto/build.proto
|
|
3
|
+
# proto-message: BuildConfig
|
|
4
|
+
|
|
5
|
+
# Location of the bash script. Should have value <github_scm.name>/<path_from_repository_root>.
|
|
6
|
+
# github_scm.name is specified in the job configuration (next section).
|
|
7
|
+
build_file: "cloud-run-mcp/.kokoro/kokoro_build.sh"
|
|
8
|
+
|
|
9
|
+
container_properties {
|
|
10
|
+
docker_image: "us-central1-docker.pkg.dev/kokoro-container-bakery/kokoro/ubuntu/ubuntu2204/full:next"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
env_vars {
|
|
14
|
+
key: "GOOGLE_CLOUD_PROJECT"
|
|
15
|
+
value: "cloud-run-mcp-server-testing"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
env_vars {
|
|
19
|
+
key: "GCP_PARENT"
|
|
20
|
+
value: "folders/138095058155"
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2022 Google LLC
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
# Fail on any error.
|
|
18
|
+
set -xe
|
|
19
|
+
|
|
20
|
+
# cd to project root
|
|
21
|
+
cd "$(dirname "$0")"/..
|
|
22
|
+
|
|
23
|
+
# Install dependencies
|
|
24
|
+
npm install
|
|
25
|
+
|
|
26
|
+
# Run tests
|
|
27
|
+
npm run test:workflows # Run tests related to all workflows
|
|
28
|
+
npm run test:projects # Run tests related to GCP projects
|
|
29
|
+
npm run test:services # Run tests related to services
|
|
30
|
+
npm run test:deploy # Run tests related to deployments
|
|
31
|
+
npm run test:gcp-auth # Run tests related to GCP authentication
|
package/CONTRIBUTING.md
CHANGED
|
@@ -74,7 +74,7 @@ To use remote MCP Server in a MCP client:
|
|
|
74
74
|
Start the MCP server locally with:
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
|
-
|
|
77
|
+
GCP_STDIO=false node /path/to/this/repo/cloud-run-mcp/mcp-server.js
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
Then, in your MCP client configuration, use the following:
|
|
@@ -84,7 +84,19 @@ Then, in your MCP client configuration, use the following:
|
|
|
84
84
|
"mcpServers": {
|
|
85
85
|
"cloud-run": {
|
|
86
86
|
"command": "npx",
|
|
87
|
-
"args": ["mcp-remote", "http://localhost:3000/
|
|
87
|
+
"args": ["mcp-remote", "http://localhost:3000/mcp"]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
or, if your client supports the `url` attribute, you can use:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"cloud-run": {
|
|
99
|
+
"url": "http://localhost:3000/mcp"
|
|
88
100
|
}
|
|
89
101
|
}
|
|
90
102
|
}
|
|
@@ -114,14 +126,17 @@ This script requires an existing Google Cloud Project ID to be provided when pro
|
|
|
114
126
|
|
|
115
127
|
## Publishing to npm
|
|
116
128
|
|
|
117
|
-
To update the [npm package]https://www.npmjs.com/package/@google-cloud/cloud-run-mcp)
|
|
129
|
+
To update the [npm package](https://www.npmjs.com/package/@google-cloud/cloud-run-mcp)
|
|
118
130
|
|
|
119
131
|
Run the following:
|
|
120
132
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
- `git checkout -b new-release`
|
|
134
|
+
- `npm test`
|
|
135
|
+
- `npm version minor`
|
|
136
|
+
- `git push --set-upstream origin new-release --follow-tags`
|
|
137
|
+
- Create a [pull request for 'new-release' on GitHub](https://github.com/GoogleCloudPlatform/cloud-run-mcp/pull/new/new-release)
|
|
138
|
+
- Get approval
|
|
139
|
+
- Rebase and merge into main
|
|
140
|
+
- On GitHub, [create a new release](https://github.com/GoogleCloudPlatform/cloud-run-mcp/releases/new) for this tag.
|
|
126
141
|
|
|
127
|
-
Then a [GitHub Action]https://github.com/GoogleCloudPlatform/cloud-run-mcp/blob/main/.github/workflows/npm-publish.yml) automatically publishes to npm when new releases are pushes.
|
|
142
|
+
Then a [GitHub Action](https://github.com/GoogleCloudPlatform/cloud-run-mcp/blob/main/.github/workflows/npm-publish.yml) automatically publishes to npm when new releases are pushes.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# MCP server
|
|
1
|
+
# Cloud Run MCP server and Gemini CLI extension
|
|
2
2
|
|
|
3
3
|
Enable MCP-compatible AI agents to deploy apps to Cloud Run.
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ Enable MCP-compatible AI agents to deploy apps to Cloud Run.
|
|
|
11
11
|
}
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Deploy from Gemini CLI and other AI-powered CLI agents:
|
|
14
|
+
Deploy from Gemini CLI and other AI-powered CLI agents:
|
|
15
15
|
|
|
16
16
|
<img src="https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/refs/heads/main/.github/images/deploycli.gif" width="800">
|
|
17
17
|
|
|
@@ -48,19 +48,58 @@ Prompts are natural language commands that can be used to perform common tasks.
|
|
|
48
48
|
- `deploy`: Deploys the current working directory to Cloud Run. If a service name is not provided, it will use the `DEFAULT_SERVICE_NAME` environment variable, or the name of the current working directory.
|
|
49
49
|
- `logs`: Gets the logs for a Cloud Run service. If a service name is not provided, it will use the `DEFAULT_SERVICE_NAME` environment variable, or the name of the current working directory.
|
|
50
50
|
|
|
51
|
+
## Environment Variables
|
|
52
|
+
|
|
53
|
+
The Cloud Run MCP server can be configured using the following environment variables:
|
|
54
|
+
|
|
55
|
+
| Variable | Description |
|
|
56
|
+
| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
57
|
+
| `GOOGLE_CLOUD_PROJECT` | The default project ID to use for Cloud Run services. |
|
|
58
|
+
| `GOOGLE_CLOUD_REGION` | The default region to use for Cloud Run services. |
|
|
59
|
+
| `DEFAULT_SERVICE_NAME` | The default service name to use for Cloud Run services. |
|
|
60
|
+
| `SKIP_IAM_CHECK` | Controls whether to check for IAM permissions for a Cloud Run service. Set to `false` to enable checks. This is `true` by default which is a recommended way to make the service public. |
|
|
61
|
+
| `ENABLE_HOST_VALIDATION` | Prevents [DNS Rebinding](https://en.wikipedia.org/wiki/DNS_rebinding) attacks by validating the Host header. This is disabled by default. |
|
|
62
|
+
| `ALLOWED_HOSTS` | Comma-separated list of allowed Host headers (if host validation is enabled). The default value is `localhost,127.0.0.1,::1`. |
|
|
51
63
|
|
|
52
64
|
## Use as a Gemini CLI extension
|
|
53
65
|
|
|
54
66
|
To install this as a [Gemini CLI](https://github.com/google-gemini/gemini-cli) extension, run the following command:
|
|
55
67
|
|
|
56
|
-
|
|
57
|
-
mkdir -p ~/.gemini/extensions/cloud-run/gemini-extension && \
|
|
58
|
-
curl -s -L https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/main/gemini-extension.json > ~/.gemini/extensions/cloud-run/gemini-extension.json && \
|
|
59
|
-
curl -s -L https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/main/gemini-extension/GEMINI.md > ~/.gemini/extensions/cloud-run/gemini-extension/GEMINI.md
|
|
60
|
-
```
|
|
68
|
+
2. Install the extension:
|
|
61
69
|
|
|
70
|
+
```bash
|
|
71
|
+
gemini extensions install https://github.com/GoogleCloudPlatform/cloud-run-mcp
|
|
72
|
+
```
|
|
62
73
|
|
|
63
|
-
|
|
74
|
+
3. Log in to your Google Cloud account using the command:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
gcloud auth login
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
4. Set up application credentials using the command:
|
|
81
|
+
```bash
|
|
82
|
+
gcloud auth application-default login
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Use in MCP Clients
|
|
86
|
+
|
|
87
|
+
### Learn how to configure your MCP client
|
|
88
|
+
|
|
89
|
+
Most MCP clients require a configuration file to be created or modified to add the MCP server.
|
|
90
|
+
|
|
91
|
+
The configuration file syntax can be different across clients. Please refer to the following links for the latest expected syntax:
|
|
92
|
+
|
|
93
|
+
- [**Antigravity**](https://antigravity.google/docs/mcp)
|
|
94
|
+
- [**Windsurf**](https://docs.windsurf.com/windsurf/mcp)
|
|
95
|
+
- [**VSCode**](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
|
|
96
|
+
- [**Claude Desktop**](https://modelcontextprotocol.io/quickstart/user)
|
|
97
|
+
- [**Cursor**](https://docs.cursor.com/context/model-context-protocol)
|
|
98
|
+
|
|
99
|
+
Once you have identified how to configure your MCP client, select one of these two options to set up the MCP server.
|
|
100
|
+
We recommend setting up as a local MCP server using Node.js.
|
|
101
|
+
|
|
102
|
+
### Set up as local MCP server
|
|
64
103
|
|
|
65
104
|
Run the Cloud Run MCP server on your local machine using local Google Cloud credentials. This is best if you are using an AI-assisted IDE (e.g. Cursor) or a desktop AI application (e.g. Claude).
|
|
66
105
|
|
|
@@ -79,7 +118,7 @@ Run the Cloud Run MCP server on your local machine using local Google Cloud cred
|
|
|
79
118
|
|
|
80
119
|
Then configure the MCP server using either Node.js or Docker:
|
|
81
120
|
|
|
82
|
-
|
|
121
|
+
#### Using Node.js
|
|
83
122
|
|
|
84
123
|
0. Install [Node.js](https://nodejs.org/en/download/) (LTS version recommended).
|
|
85
124
|
|
|
@@ -106,7 +145,7 @@ Then configure the MCP server using either Node.js or Docker:
|
|
|
106
145
|
}
|
|
107
146
|
```
|
|
108
147
|
|
|
109
|
-
|
|
148
|
+
#### Using Docker
|
|
110
149
|
|
|
111
150
|
See Docker's [MCP catalog](https://hub.docker.com/mcp/server/cloud-run-mcp/overview), or use these manual instructions:
|
|
112
151
|
|
|
@@ -134,7 +173,7 @@ See Docker's [MCP catalog](https://hub.docker.com/mcp/server/cloud-run-mcp/overv
|
|
|
134
173
|
}
|
|
135
174
|
```
|
|
136
175
|
|
|
137
|
-
|
|
176
|
+
### Set up as remote MCP server
|
|
138
177
|
|
|
139
178
|
> [!WARNING]
|
|
140
179
|
> Do not use the remote MCP server without authentication. In the following instructions, we will use IAM authentication to secure the connection to the MCP server from your local machine. This is important to prevent unauthorized access to your Google Cloud resources.
|
|
@@ -195,3 +234,5 @@ With this option, you will only be able to deploy code to the same Google Cloud
|
|
|
195
234
|
"args": ["-y", "mcp-remote", "http://localhost:3000/sse"]
|
|
196
235
|
}
|
|
197
236
|
```
|
|
237
|
+
|
|
238
|
+
The Google Cloud Platform Terms of Service (available at https://cloud.google.com/terms/) and the Data Processing and Security Terms (available at https://cloud.google.com/terms/data-processing-terms) do not apply to any component of the Cloud Run MCP Server software.
|
package/REVIEWING.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Reviewing Pull Requests
|
|
2
|
+
|
|
3
|
+
This document provides guidelines for reviewing Pull Requests.
|
|
4
|
+
|
|
5
|
+
## Guidelines
|
|
6
|
+
|
|
7
|
+
### Presubmit Tests
|
|
8
|
+
|
|
9
|
+
Running presubmit tests is a mandatory requirement for Pull Requests to be eligible for submission.
|
|
10
|
+
|
|
11
|
+
**Before triggering tests:**
|
|
12
|
+
Review the code changes, especially new or modified tests, to ensure they do not contain any malicious or harmful code that could unnecessarily consume or harm Google's resources during test execution. In particular, ensure the tests:
|
|
13
|
+
|
|
14
|
+
- **Do not modify environment variables:** The tests should not modify environment variables in an unexpected or harmful way.
|
|
15
|
+
- **Do not consume excessive resources:** Ensure tests do not create an excessive number of Google Cloud projects or other high-cost resources.
|
|
16
|
+
- **Do not contain hardcoded credentials:** Credentials should not be present in the code.
|
|
17
|
+
- **Do not rely on untrusted external dependencies:** Any new external dependencies should be reviewed for trustworthiness.
|
|
18
|
+
|
|
19
|
+
**Triggering tests:**
|
|
20
|
+
If the code is safe to run, trigger presubmit tests by adding a comment with `kokoro:run` to the Pull Request. Tests are run via Kokoro.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Code that can be deployed
|
|
4
4
|
|
|
5
5
|
Only web servers can be deployed using this MCP server.
|
|
6
|
-
The code needs to listen for HTTP
|
|
6
|
+
The code needs to listen for HTTP requests on the port defined by the $PORT environment variable or 8080.
|
|
7
7
|
|
|
8
8
|
### Supported languages
|
|
9
9
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Google LLC
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Lists all accessible Google Cloud Billing Accounts.
|
|
19
|
+
* @async
|
|
20
|
+
* @function listBillingAccounts
|
|
21
|
+
* @returns {Promise<Array<{name: string, displayName: string, open: boolean}>>} A promise that resolves to an array of billing account objects,
|
|
22
|
+
* each with 'name', 'displayName', and 'open' status. Returns an empty array on error.
|
|
23
|
+
*/
|
|
24
|
+
export async function listBillingAccounts() {
|
|
25
|
+
const { CloudBillingClient } = await import('@google-cloud/billing');
|
|
26
|
+
const client = new CloudBillingClient();
|
|
27
|
+
try {
|
|
28
|
+
const [accounts] = await client.listBillingAccounts();
|
|
29
|
+
if (!accounts || accounts.length === 0) {
|
|
30
|
+
console.log('No billing accounts found.');
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return accounts.map((account) => ({
|
|
34
|
+
name: account.name, // e.g., billingAccounts/0X0X0X-0X0X0X-0X0X0X
|
|
35
|
+
displayName: account.displayName,
|
|
36
|
+
open: account.open,
|
|
37
|
+
}));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('Error listing GCP billing accounts:', error);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Attaches a Google Cloud Project to a specified Billing Account.
|
|
46
|
+
* @async
|
|
47
|
+
* @function attachProjectToBillingAccount
|
|
48
|
+
* @param {string} projectId - The ID of the project to attach.
|
|
49
|
+
* @param {string} billingAccountName - The resource name of the billing account (e.g., 'billingAccounts/0X0X0X-0X0X0X-0X0X0X').
|
|
50
|
+
* @returns {Promise<object|null>} A promise that resolves to the updated project billing information object if successful, or null on error.
|
|
51
|
+
*/
|
|
52
|
+
export async function attachProjectToBillingAccount(
|
|
53
|
+
projectId,
|
|
54
|
+
billingAccountName
|
|
55
|
+
) {
|
|
56
|
+
const { CloudBillingClient } = await import('@google-cloud/billing');
|
|
57
|
+
const client = new CloudBillingClient();
|
|
58
|
+
const projectName = `projects/${projectId}`;
|
|
59
|
+
|
|
60
|
+
if (!projectId) {
|
|
61
|
+
console.error('Error: projectId is required.');
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (
|
|
65
|
+
!billingAccountName ||
|
|
66
|
+
!billingAccountName.startsWith('billingAccounts/')
|
|
67
|
+
) {
|
|
68
|
+
console.error(
|
|
69
|
+
'Error: billingAccountName is required and must be in the format "billingAccounts/XXXXXX-XXXXXX-XXXXXX".'
|
|
70
|
+
);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
console.log(
|
|
76
|
+
`Attempting to attach project ${projectId} to billing account ${billingAccountName}...`
|
|
77
|
+
);
|
|
78
|
+
const [updatedBillingInfo] = await client.updateProjectBillingInfo({
|
|
79
|
+
name: projectName,
|
|
80
|
+
projectBillingInfo: {
|
|
81
|
+
billingAccountName: billingAccountName,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
console.log(
|
|
85
|
+
`Successfully attached project ${projectId} to billing account ${billingAccountName}.`
|
|
86
|
+
);
|
|
87
|
+
console.log(`Billing enabled: ${updatedBillingInfo.billingEnabled}`);
|
|
88
|
+
return updatedBillingInfo;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(
|
|
91
|
+
`Error attaching project ${projectId} to billing account ${billingAccountName}:`,
|
|
92
|
+
error.message || error
|
|
93
|
+
);
|
|
94
|
+
// Log more details if available, e.g. error.details
|
|
95
|
+
// if (error.details) console.error("Error details:", error.details);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Checks if billing is enabled for a given project.
|
|
102
|
+
* @async
|
|
103
|
+
* @function isBillingEnabled
|
|
104
|
+
* @param {string} projectId - The ID of the project to check.
|
|
105
|
+
* @returns {Promise<boolean>} A promise that resolves to true if billing is enabled, false otherwise.
|
|
106
|
+
*/
|
|
107
|
+
export async function isBillingEnabled(projectId) {
|
|
108
|
+
const { CloudBillingClient } = await import('@google-cloud/billing');
|
|
109
|
+
const client = new CloudBillingClient();
|
|
110
|
+
const projectName = `projects/${projectId}`;
|
|
111
|
+
try {
|
|
112
|
+
// getProjectBillingInfo requires cloudbilling.googleapis.com API to check billing status
|
|
113
|
+
// https://docs.cloud.google.com/billing/docs/reference/rest/v1/projects/getBillingInfo
|
|
114
|
+
const [billingInfo] = await client.getProjectBillingInfo({
|
|
115
|
+
name: projectName,
|
|
116
|
+
});
|
|
117
|
+
return billingInfo.billingEnabled;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error(
|
|
120
|
+
`Error checking billing status for project ${projectId}:`,
|
|
121
|
+
error.message || error
|
|
122
|
+
);
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Ensures billing is enabled for a project. If not, attempts to enable it
|
|
129
|
+
* by attaching the single open billing account if one is found.
|
|
130
|
+
* @param {object} context - The context object containing clients and other parameters.
|
|
131
|
+
* @param {string} projectId The project ID to check billing for.
|
|
132
|
+
* @param {function} progressCallback A callback function for progress updates.
|
|
133
|
+
*/
|
|
134
|
+
export async function ensureBillingEnabled(
|
|
135
|
+
context,
|
|
136
|
+
projectId,
|
|
137
|
+
progressCallback
|
|
138
|
+
) {
|
|
139
|
+
if (!(await isBillingEnabled(projectId))) {
|
|
140
|
+
// Billing is disabled, try to fix it.
|
|
141
|
+
const accounts = await listBillingAccounts();
|
|
142
|
+
|
|
143
|
+
if (accounts && accounts.length === 1 && accounts[0].open) {
|
|
144
|
+
// Exactly one open account found, try to attach it.
|
|
145
|
+
const account = accounts[0];
|
|
146
|
+
const attemptMessage = `Billing is not enabled for project ${projectId}. Found one open billing account: ${account.displayName} (${account.name}). Attempting to attach it...`;
|
|
147
|
+
console.log(attemptMessage);
|
|
148
|
+
if (progressCallback)
|
|
149
|
+
progressCallback({ level: 'info', data: attemptMessage });
|
|
150
|
+
|
|
151
|
+
const attachmentResult = await attachProjectToBillingAccount(
|
|
152
|
+
projectId,
|
|
153
|
+
account.name
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (!attachmentResult || !attachmentResult.billingEnabled) {
|
|
157
|
+
const attachFailMessage = `Failed to automatically attach project ${projectId} to billing account ${account.name}. Please enable billing manually: https://console.cloud.google.com/billing/linkedaccount?project=${projectId}`;
|
|
158
|
+
if (progressCallback)
|
|
159
|
+
progressCallback({ level: 'error', data: attachFailMessage });
|
|
160
|
+
throw new Error(attachFailMessage);
|
|
161
|
+
}
|
|
162
|
+
const attachSuccessMessage = `Successfully attached project ${projectId} to billing account ${account.name}.`;
|
|
163
|
+
console.log(attachSuccessMessage);
|
|
164
|
+
if (progressCallback)
|
|
165
|
+
progressCallback({ level: 'info', data: attachSuccessMessage });
|
|
166
|
+
// If we get here, billing is now enabled, and we can proceed to API checks.
|
|
167
|
+
} else {
|
|
168
|
+
// Cannot auto-attach. Throw error.
|
|
169
|
+
let reason;
|
|
170
|
+
if (!accounts || accounts.length === 0) {
|
|
171
|
+
reason = 'no billing accounts were found';
|
|
172
|
+
} else if (accounts.length > 1) {
|
|
173
|
+
reason = 'multiple billing accounts were found';
|
|
174
|
+
} else {
|
|
175
|
+
reason = `the only available billing account '${accounts[0].displayName}' is not open`;
|
|
176
|
+
}
|
|
177
|
+
const errorMessage = `Billing is not enabled for project ${projectId}, and it could not be enabled automatically because ${reason}. Please enable billing to use Google Cloud services: https://console.cloud.google.com/billing/linkedaccount?project=${projectId}`;
|
|
178
|
+
if (progressCallback)
|
|
179
|
+
progressCallback({ level: 'error', data: errorMessage });
|
|
180
|
+
throw new Error(errorMessage);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|