Skip to content

Add code samples for Connect Gateway API #13311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
May 1, 2025
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
67d6f11
Add code samples for Connect Gateway API
hodaaaaaaaaaa Apr 19, 2025
be360b8
Update connectgateway/main.py
hodaaaaaaaaaa Apr 22, 2025
864c7b4
Update connectgateway/main.py
hodaaaaaaaaaa Apr 22, 2025
596965c
Update connectgateway/main.py
hodaaaaaaaaaa Apr 22, 2025
6aeda6c
Update connectgateway/main.py
hodaaaaaaaaaa Apr 22, 2025
144544e
Update connectgateway/main.py
hodaaaaaaaaaa Apr 22, 2025
0c376e2
Use env variables for membership fields
hodaaaaaaaaaa Apr 22, 2025
fda07e2
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
ac96daa
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
ab59ff7
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
69a4ce9
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
36ad43a
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
30aa882
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
b9a120d
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
e54c6de
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
eb3d471
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
b50bf07
Add tests to the Connect Gateway sample
hodaaaaaaaaaa Apr 30, 2025
37641a5
address PR comments
hodaaaaaaaaaa May 1, 2025
8caaa0b
address PR comments
hodaaaaaaaaaa May 1, 2025
a7860c7
address PR comments
hodaaaaaaaaaa May 1, 2025
e52edab
address PR comments
hodaaaaaaaaaa May 1, 2025
59fcb6c
address PR comments
hodaaaaaaaaaa May 1, 2025
e193dd1
address PR comments
hodaaaaaaaaaa May 1, 2025
81bf16b
use ADC instead of service account
hodaaaaaaaaaa May 1, 2025
d80870d
use ADC instead of service account
hodaaaaaaaaaa May 1, 2025
8277d4a
use ADC instead of service account
hodaaaaaaaaaa May 1, 2025
7019e12
use ADC instead of service account
hodaaaaaaaaaa May 1, 2025
e09c5cc
use ADC instead of service account
hodaaaaaaaaaa May 1, 2025
80c6d7c
Update connectgateway/requirements.txt
glasnt May 1, 2025
d7cbc11
add back base noxfile_config, deleted accidentally
hodaaaaaaaaaa May 1, 2025
2a5f0af
add back base noxfile_config, deleted accidentally
hodaaaaaaaaaa May 1, 2025
4ddfaa9
address lint errors
hodaaaaaaaaaa May 1, 2025
3a36aae
address lint errors
hodaaaaaaaaaa May 1, 2025
818eab3
Update connectgateway/requirements-test.txt
glasnt May 1, 2025
abd278b
Update connectgateway/requirements-test.txt
glasnt May 1, 2025
6d7d7f1
Cleanup excess comments
glasnt May 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
/bigquery-datatransfer/**/* @GoogleCloudPlatform/api-bigquery @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/bigquery-migration/**/* @GoogleCloudPlatform/api-bigquery @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/bigquery-reservation/**/* @GoogleCloudPlatform/api-bigquery @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/connectgateway/**/* @GoogleCloudPlatform/connectgateway @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/dlp/**/* @GoogleCloudPlatform/googleapis-dlp @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/functions/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/functions-framework-google @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
/healthcare/**/* @GoogleCloudPlatform/healthcare-life-sciences @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers
Expand Down
4 changes: 4 additions & 0 deletions .github/blunderbuss.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ assign_prs_by:
- "api: dataplex"
to:
- GoogleCloudPlatform/googleapi-dataplex
- labels:
- "api: connectgateway"
to:
- GoogleCloudPlatform/connectgateway
# Self-service individuals
- labels:
- "api: auth"
Expand Down
10 changes: 10 additions & 0 deletions connectgateway/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Sample Snippets for Connect Gateway API

## Quick Start

In order to run these samples, you first need to go through the following steps:

1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project)
2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project)
3. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html)
4. [Setup Connect Gateway.](https://cloud.google.com/kubernetes-engine/enterprise/multicluster-management/gateway/setup)
97 changes: 97 additions & 0 deletions connectgateway/get_namespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright 2025 Google LLC
#
# 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
#
# http://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.

# [START connectgateway_get_namespace]
import os
import sys

from google.api_core import exceptions
import google.auth
from google.auth.transport import requests
from google.cloud.gkeconnect import gateway_v1
from kubernetes import client


SCOPES = ['https://www.googleapis.com/auth/cloud-platform']


def get_gateway_url(membership_name: str, location: str) -> str:
"""Fetches the GKE Connect Gateway URL for the specified membership."""
try:
client_options = {}
if location != "global":
# If the location is not global, the endpoint needs to be set to the regional endpoint.
regional_endpoint = f"{location}-connectgateway.googleapis.com"
client_options = {"api_endpoint": regional_endpoint}
gateway_client = gateway_v1.GatewayControlClient(client_options=client_options)
request = gateway_v1.GenerateCredentialsRequest()
request.name = membership_name
response = gateway_client.generate_credentials(request=request)
print(f'GKE Connect Gateway Endpoint: {response.endpoint}')
if not response.endpoint:
print("Error: GKE Connect Gateway Endpoint is empty.")
sys.exit(1)
return response.endpoint
except exceptions.NotFound as e:
print(f'Membership not found: {e}')
sys.exit(1)
except Exception as e:
print(f'Error fetching GKE Connect Gateway URL: {e}')
sys.exit(1)


def configure_kubernetes_client(gateway_url: str) -> client.CoreV1Api:
"""Configures the Kubernetes client with the GKE Connect Gateway URL and credentials."""

configuration = client.Configuration()

# Configure the API client with the custom host.
configuration.host = gateway_url

# Configure API key using default auth.
credentials, _ = google.auth.default(scopes=SCOPES)
auth_req = requests.Request()
credentials.refresh(auth_req)
configuration.api_key = {'authorization': f'Bearer {credentials.token}'}

api_client = client.ApiClient(configuration=configuration)
return client.CoreV1Api(api_client)


def get_default_namespace(api_client: client.CoreV1Api) -> None:
"""Get default namespace in the Kubernetes cluster."""
try:
namespace = api_client.read_namespace(name="default")
return namespace
except client.ApiException as e:
print(f"Error getting default namespace: {e}\nStatus: {e.status}\nReason: {e.reason}")
sys.exit(1)


def get_namespace(membership_name: str, location: str) -> None:
"""Main function to connect to the cluster and get the default namespace."""
gateway_url = get_gateway_url(membership_name, location)
core_v1_api = configure_kubernetes_client(gateway_url)
namespace = get_default_namespace(core_v1_api)
print(f"\nDefault Namespace:\n{namespace}")

# [END connectgateway_get_namespace]

return namespace


if __name__ == "__main__":
MEMBERSHIP_NAME = os.environ.get('MEMBERSHIP_NAME')
MEMBERSHIP_LOCATION = os.environ.get("MEMBERSHIP_LOCATION")
namespace = get_namespace(MEMBERSHIP_NAME, MEMBERSHIP_LOCATION)
92 changes: 92 additions & 0 deletions connectgateway/get_namespace_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright 2025 Google LLC
#
# 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
#
# http://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.

import os
from time import sleep
import uuid


from google.cloud import container_v1 as gke

import pytest

import get_namespace

PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
ZONE = "us-central1-a"
REGION = "us-central1"
CLUSTER_NAME = f"cluster-{uuid.uuid4().hex[:10]}"


@pytest.fixture(autouse=True)
def setup_and_tear_down() -> None:
# Create the cluster.
create_cluster(PROJECT_ID, ZONE, CLUSTER_NAME)

# Run the tests here.
yield

# Delete the cluster.
delete_cluster(PROJECT_ID, ZONE, CLUSTER_NAME)


def poll_operation(client: gke.ClusterManagerClient, op_id: str) -> None:

while True:
# Make GetOperation request
operation = client.get_operation({"name": op_id})
# Print the Operation Information
print(operation)

# Stop polling when Operation is done.
if operation.status == gke.Operation.Status.DONE:
break

# Wait 30 seconds before polling again
sleep(30)


def create_cluster(project_id: str, location: str, cluster_name: str) -> None:
"""Create a new GKE cluster in the given GCP Project and Zone/Region."""
# Initialize the Cluster management client.
client = gke.ClusterManagerClient()
cluster_location = client.common_location_path(project_id, location)
cluster_def = {
"name": str(cluster_name),
"initial_node_count": 1,
"fleet": {"project": str(project_id)},
}

# Create the request object with the location identifier.
request = {"parent": cluster_location, "cluster": cluster_def}
create_response = client.create_cluster(request)
op_identifier = f"{cluster_location}/operations/{create_response.name}"
# poll for the operation status and schedule a retry until the cluster is created
poll_operation(client, op_identifier)


def delete_cluster(project_id: str, location: str, cluster_name: str) -> None:
"""Delete the created GKE cluster."""
client = gke.ClusterManagerClient()
cluster_location = client.common_location_path(project_id, location)
cluster_name = f"{cluster_location}/clusters/{cluster_name}"
client.delete_cluster({"name": cluster_name})


def test_get_namespace() -> None:
membership_name = f"projects/{PROJECT_ID}/locations/{REGION}/memberships/{CLUSTER_NAME}"
results = get_namespace.get_namespace(membership_name, REGION)

assert results is not None
assert results.metadata.name == "default"
22 changes: 22 additions & 0 deletions connectgateway/noxfile_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2025 Google LLC
#
# 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
#
# http://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.

TEST_CONFIG_OVERRIDE = {
# You can opt out from the test for specific Python versions.
"ignored_versions": ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"],
"enforce_type_hints": True,
"gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
"pip_version_override": None,
"envs": {},
}
2 changes: 2 additions & 0 deletions connectgateway/requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
google-cloud-container==21.2.4
pytest==21.2.4
4 changes: 4 additions & 0 deletions connectgateway/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
google-cloud-gke-connect-gateway==0.10.3
google-auth==2.38.0
kubernetes==32.0.1
google-api-core==2.24.2