-
Notifications
You must be signed in to change notification settings - Fork 6.5k
feat: migrate code from googleapis/python-container #8451
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
Changes from all commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
f432083
feat!: migrate to microgenerator (#33)
arithmetic1728 91547b0
docs(samples): add usage samples to show handling of LRO response Ope…
Shabirmean 4da083a
chore: Adding support for pytest-xdist and pytest-parallel (#204)
gcf-owl-bot[bot] 4dd369c
chore(deps): update all dependencies (#206)
renovate-bot 8caf13e
chore(deps): update dependency google-cloud-container to v2.10.6 (#207)
renovate-bot f9687c6
chore(deps): update dependency pytest to v7.1.0 (#209)
renovate-bot cae7f4d
chore(deps): update dependency pytest to v7.1.1 (#211)
renovate-bot 72c72db
fix: test cleanup stages with try finally (#212)
Shabirmean f9080ce
chore(deps): update dependency google-cloud-container to v2.10.7 (#215)
renovate-bot c93f8df
chore(python): use black==22.3.0 (#217)
gcf-owl-bot[bot] 1127deb
chore(python): add nox session to sort python imports (#229)
gcf-owl-bot[bot] bdc99b0
chore(deps): update dependency pytest to v7.1.2 (#232)
renovate-bot 7920f17
chore(deps): update dependency backoff to v2 (#233)
renovate-bot 48b42ae
chore(deps): update dependency backoff to v2.0.1 (#235)
renovate-bot 0d6ae6c
fix: require python 3.7+ (#266)
gcf-owl-bot[bot] e79b44e
chore(deps): update all dependencies (#258)
renovate-bot 73bc1bd
chore(deps): update all dependencies (#271)
renovate-bot 40614e6
chore(deps): update all dependencies to v2.11.1 (#276)
renovate-bot ccf1085
chore(deps): update dependency google-cloud-container to v2.11.2 (#280)
renovate-bot bf9b246
chore(deps): update dependency pytest to v7.1.3 (#291)
renovate-bot 490f770
chore: detect samples tests in nested directories (#295)
gcf-owl-bot[bot] 3e78978
chore(deps): update dependency google-cloud-container to v2.12.0 (#299)
renovate-bot 8f1a926
chore(deps): update dependency google-cloud-container to v2.12.1 (#303)
renovate-bot 566162e
chore(deps): update dependency backoff to v2.2.1 (#304)
renovate-bot fa3cac8
chore(deps): update dependency google-cloud-container to v2.12.2 (#308)
renovate-bot 857a2ad
chore(deps): update dependency pytest to v7.2.0 (#310)
renovate-bot b2d82b8
chore(deps): update dependency google-cloud-container to v2.13.0 (#311)
renovate-bot 5a680f1
Merge remote-tracking branch 'migration/main' into python-container-m…
donmccasland ac3c355
Updating license headers
donmccasland 07e128e
Merge branch 'main' into python-container-migration
nicain f282fe2
Update container/snippets/noxfile.py
donmccasland 53e3bce
lint fix
donmccasland 10625cf
Adding CODEOWNERS definition
donmccasland 583de91
Update container/CONTRIBUTING.md
donmccasland df1d2c0
Update container/AUTHORING_GUIDE.md
donmccasland 0621d06
Removing noxfile
donmccasland 0adad32
Adding blunderbuss
donmccasland 933dd05
Merge branch 'main' into python-container-migration
donmccasland d9de181
Merge branch 'main' into python-container-migration
kweinmeister 444c340
Extending test timeout to 1 hour because cluster creation takes forever
donmccasland 526fcc0
Merge branch 'main' into python-container-migration
dandhlee 14ecc9f
Merge branch 'main' into python-container-migration
dandhlee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/AUTHORING_GUIDE.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/CONTRIBUTING.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Samples | ||
|
||
All the samples are self contained unless they are placed inside their own folders. The samples use [Application Default Credentails (ADC)](https://cloud.google.com/docs/authentication/production#automatically) to authenticate with GCP. So make sure ADC is setup correctly _(i.e. `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set)_ before running the samples. Some sample might require additional python modules to be installed. | ||
|
||
You can run samples as follows: | ||
|
||
```python | ||
python <sample_name.py> <arg1> <arg2> ... | ||
``` | ||
|
||
You can run the following command to find the usage and arguments for the samples: | ||
|
||
```python | ||
python <sample_name.py> -h | ||
``` | ||
```bash | ||
# example | ||
python quickstart.py -h | ||
|
||
usage: quickstart.py [-h] project_id zone | ||
|
||
positional arguments: | ||
project_id Google Cloud project ID | ||
zone GKE Cluster zone | ||
|
||
optional arguments: | ||
-h, --help show this help message and exit | ||
``` | ||
|
||
### Quickstart sample | ||
- [**quickstart.py**](quickstart.py): A simple example to list the GKE clusters in a given GCP project and zone. The sample uses the [`list_clusters()`](https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.services.cluster_manager.ClusterManagerClient#google_cloud_container_v1_services_cluster_manager_ClusterManagerClient_list_clusters) API to fetch the list of cluster. | ||
|
||
|
||
### Long running operation sample | ||
|
||
The following samples are examples of operations that take a while to complete. | ||
For example _creating a cluster_ in GKE can take a while to set up the cluster | ||
nodes, networking and configuring Kubernetes. Thus, calls to such long running | ||
APIs return an object of type [`Operation`](https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.types.Operation). We can | ||
then use the id of the returned operation to **poll** the [`get_operation()`](https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.services.cluster_manager.ClusterManagerClient#google_cloud_container_v1_services_cluster_manager_ClusterManagerClient_get_operation) API to check for it's status. You can see the | ||
different statuses it can be in, in [this proto definition](https://github.com/googleapis/googleapis/blob/master/google/container/v1/cluster_service.proto#L1763-L1778). | ||
|
||
- [**create_cluster.py**](create_cluster.py): An example of creating a GKE cluster _(with mostly the defaults)_. This example shows how to handle responses of type [`Operation`](https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.types.Operation) that reperesents a long running operation. The example uses the python module [`backoff`](https://github.com/litl/backoff) to handle a graceful exponential backoff retry mechanism to check if the `Operation` has completed. | ||
|
||
- [**delete_cluster.py**](delete_cluster.py): An example of deleting a GKE cluster. This example shows how to handle responses of type [`Operation`](https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.types.Operation) that reperesents a long running operation. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2022 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 gke_create_cluster] | ||
import argparse | ||
import sys | ||
from typing import Dict | ||
|
||
import backoff | ||
from google.cloud import container_v1 | ||
|
||
|
||
def on_success(details: Dict[str, str]) -> None: | ||
""" | ||
A handler function to pass into the retry backoff algorithm as the function | ||
to be executed upon a successful attempt. | ||
|
||
Read the `Event handlers` section of the backoff python module at: | ||
https://pypi.org/project/backoff/ | ||
""" | ||
print("Successfully created cluster after {elapsed:0.1f} seconds".format(**details)) | ||
|
||
|
||
def on_failure(details: Dict[str, str]) -> None: | ||
""" | ||
A handler function to pass into the retry backoff algorithm as the function | ||
to be executed upon a failed attempt. | ||
|
||
Read the `Event handlers` section of the backoff python module at: | ||
https://pypi.org/project/backoff/ | ||
""" | ||
print("Backing off {wait:0.1f} seconds after {tries} tries".format(**details)) | ||
|
||
|
||
@backoff.on_predicate( | ||
# the backoff algorithm to use. we use exponential backoff here | ||
backoff.expo, | ||
# the test function on the return value to determine if a retry is necessary | ||
lambda x: x != container_v1.Operation.Status.DONE, | ||
# maximum number of times to retry before giving up | ||
max_tries=20, | ||
# function to execute upon a failure and when a retry a scheduled | ||
on_backoff=on_failure, | ||
# function to execute upon a successful attempt and no more retries needed | ||
on_success=on_success, | ||
) | ||
def poll_for_op_status( | ||
client: container_v1.ClusterManagerClient, op_id: str | ||
) -> container_v1.Operation.Status: | ||
""" | ||
This function calls the Operation API in GCP with the given operation id. It | ||
serves as a simple retry function that fetches the operation and returns | ||
it's status. | ||
|
||
We use the 'backoff' python module to provide us the implementation of the | ||
backoff & retry strategy. The function is annotated with the `backoff` | ||
python module to schedule this function based on a reasonable backoff | ||
algorithm. | ||
""" | ||
|
||
op = client.get_operation({"name": op_id}) | ||
return op.status | ||
|
||
|
||
def create_cluster(project_id: str, location: str, cluster_name: str) -> None: | ||
"""Create a new GKE cluster in the given GCP Project and Zone""" | ||
# Initialize the Cluster management client. | ||
client = container_v1.ClusterManagerClient() | ||
# Create a fully qualified location identifier of form `projects/{project_id}/location/{zone}'. | ||
cluster_location = client.common_location_path(project_id, location) | ||
cluster_def = { | ||
"name": cluster_name, | ||
"initial_node_count": 2, | ||
"node_config": {"machine_type": "e2-standard-2"}, | ||
} | ||
# 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_for_op_status(client, op_identifier) | ||
|
||
|
||
# [END gke_create_cluster] | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description=__doc__, | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
) | ||
parser.add_argument("project_id", help="Google Cloud project ID") | ||
parser.add_argument("zone", help="GKE Cluster zone") | ||
parser.add_argument("cluster_name", help="Name to be given to the GKE Cluster") | ||
args = parser.parse_args() | ||
|
||
if len(sys.argv) != 4: | ||
parser.print_usage() | ||
sys.exit(1) | ||
|
||
create_cluster(args.project_id, args.zone, args.cluster_name) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2022 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 | ||
import uuid | ||
|
||
import backoff | ||
from google.cloud import container_v1 as gke | ||
import pytest | ||
|
||
import create_cluster as gke_create | ||
|
||
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] | ||
ZONE = "us-central1-b" | ||
CLUSTER_NAME = f"py-container-repo-test-{uuid.uuid4().hex[:10]}" | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def setup_and_tear_down() -> None: | ||
|
||
# nohing to setup here | ||
|
||
# run the tests here | ||
yield | ||
|
||
try: | ||
# delete the cluster | ||
client = gke.ClusterManagerClient() | ||
cluster_location = client.common_location_path(PROJECT_ID, ZONE) | ||
cluster_name = f"{cluster_location}/clusters/{CLUSTER_NAME}" | ||
op = client.delete_cluster({"name": cluster_name}) | ||
op_id = f"{cluster_location}/operations/{op.name}" | ||
|
||
finally: | ||
# schedule a retry to ensure the cluster is deleted | ||
@backoff.on_predicate( | ||
backoff.expo, lambda x: x != gke.Operation.Status.DONE, max_tries=20 | ||
) | ||
def wait_for_delete() -> gke.Operation.Status: | ||
return client.get_operation({"name": op_id}).status | ||
|
||
wait_for_delete() | ||
|
||
|
||
def test_create_clusters(capsys: object) -> None: | ||
gke_create.create_cluster(PROJECT_ID, ZONE, CLUSTER_NAME) | ||
out, _ = capsys.readouterr() | ||
|
||
assert "Backing off " in out | ||
assert "Successfully created cluster after" in out | ||
|
||
client = gke.ClusterManagerClient() | ||
cluster_location = client.common_location_path(PROJECT_ID, ZONE) | ||
list_response = client.list_clusters({"parent": cluster_location}) | ||
|
||
list_of_clusters = [] | ||
for cluster in list_response.clusters: | ||
list_of_clusters.append(cluster.name) | ||
|
||
assert CLUSTER_NAME in list_of_clusters |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2022 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 gke_delete_cluster] | ||
import argparse | ||
import sys | ||
from typing import Dict | ||
|
||
import backoff | ||
from google.cloud import container_v1 | ||
|
||
|
||
def on_success(details: Dict[str, str]) -> None: | ||
""" | ||
A handler function to pass into the retry backoff algorithm as the function | ||
to be executed upon a successful attempt. | ||
|
||
Read the `Event handlers` section of the backoff python module at: | ||
https://pypi.org/project/backoff/ | ||
""" | ||
print("Successfully deleted cluster after {elapsed:0.1f} seconds".format(**details)) | ||
|
||
|
||
def on_failure(details: Dict[str, str]) -> None: | ||
""" | ||
A handler function to pass into the retry backoff algorithm as the function | ||
to be executed upon a failed attempt. | ||
|
||
Read the `Event handlers` section of the backoff python module at: | ||
https://pypi.org/project/backoff/ | ||
""" | ||
print("Backing off {wait:0.1f} seconds after {tries} tries".format(**details)) | ||
|
||
|
||
@backoff.on_predicate( | ||
# the backoff algorithm to use. we use exponential backoff here | ||
backoff.expo, | ||
# the test function on the return value to determine if a retry is necessary | ||
lambda x: x != container_v1.Operation.Status.DONE, | ||
# maximum number of times to retry before giving up | ||
max_tries=20, | ||
# function to execute upon a failure and when a retry is scheduled | ||
on_backoff=on_failure, | ||
# function to execute upon a successful attempt and no more retries needed | ||
on_success=on_success, | ||
) | ||
def poll_for_op_status( | ||
client: container_v1.ClusterManagerClient, op_id: str | ||
) -> container_v1.Operation.Status: | ||
""" | ||
A simple retry function that fetches the operation and returns it's status. | ||
|
||
The function is annotated with the `backoff` python module to schedule this | ||
function based on a reasonable backoff algorithm | ||
""" | ||
|
||
op = client.get_operation({"name": op_id}) | ||
return op.status | ||
|
||
|
||
def delete_cluster(project_id: str, location: str, cluster_name: str) -> None: | ||
"""Delete an existing GKE cluster in the given GCP Project and Zone""" | ||
|
||
# Initialize the Cluster management client. | ||
client = container_v1.ClusterManagerClient() | ||
# Create a fully qualified location identifier of form `projects/{project_id}/location/{zone}'. | ||
cluster_location = client.common_location_path(project_id, location) | ||
cluster_name = f"{cluster_location}/clusters/{cluster_name}" | ||
# Create the request object with the location identifier. | ||
request = {"name": cluster_name} | ||
delete_response = client.delete_cluster(request) | ||
op_identifier = f"{cluster_location}/operations/{delete_response.name}" | ||
# poll for the operation status until the cluster is deleted | ||
poll_for_op_status(client, op_identifier) | ||
|
||
|
||
# [END gke_delete_cluster] | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description=__doc__, | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
) | ||
parser.add_argument("project_id", help="Google Cloud project ID") | ||
parser.add_argument("zone", help="GKE Cluster zone") | ||
parser.add_argument("cluster_name", help="Name to be given to the GKE Cluster") | ||
args = parser.parse_args() | ||
|
||
if len(sys.argv) != 4: | ||
parser.print_usage() | ||
sys.exit(1) | ||
|
||
delete_cluster(args.project_id, args.zone, args.cluster_name) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.