diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8dd83b4d65b0..4ad237823ae4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,6 +28,7 @@ /cdn/**/* @mpwarres @GoogleCloudPlatform/python-samples-reviewers /cloudbuild/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /cloud-sql/**/* @GoogleCloudPlatform/infra-db-dpes @GoogleCloudPlatform/python-samples-reviewers +/cloud_tasks/**/* @GoogleCloudPlatform/infra-db-dpes @GoogleCloudPlatform/python-samples-reviewers /codelabs/**/* @GoogleCloudPlatform/python-samples-reviewers /composer/**/* @leahecole @rachael-ds @rafalbiegacz @GoogleCloudPlatform/python-samples-reviewers /compute/**/* @m-strzelczyk @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index b9c52c6cfdd3..1569d57902d4 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -164,6 +164,10 @@ assign_prs_by: - 'api: talent' to: - GoogleCloudPlatform/python-samples-reviewers +- labels: + - 'api: cloudtasks' + to: + - GoogleCloudPlatform/infra-db-dpes assign_issues: - GoogleCloudPlatform/python-samples-owners diff --git a/cloud_tasks/snippets/create_http_task.py b/cloud_tasks/snippets/create_http_task.py new file mode 100644 index 000000000000..fb035f62c508 --- /dev/null +++ b/cloud_tasks/snippets/create_http_task.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# Copyright 2022 Google, Inc. +# +# 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. + +from __future__ import print_function + +import argparse + + +def create_http_task( + project, + queue, + location, + url, + payload=None, + in_seconds=None, + task_name=None, + deadline=None, +): + # [START cloud_tasks_create_http_task] + """Create a task for a given queue with an arbitrary payload.""" + + import datetime + import json + + from google.cloud import tasks_v2 + from google.protobuf import duration_pb2, timestamp_pb2 + + # Create a client. + client = tasks_v2.CloudTasksClient() + + # TODO(developer): Uncomment these lines and replace with your values. + # project = 'my-project-id' + # queue = 'my-queue' + # location = 'us-central1' + # url = 'https://example.com/task_handler' + # payload = 'hello' or {'param': 'value'} for application/json + # in_seconds = 180 + # task_name = 'my-unique-task' + # deadline = 900 + + # Construct the fully qualified queue name. + parent = client.queue_path(project, location, queue) + + # Construct the request body. + task = { + "http_request": { # Specify the type of request. + "http_method": tasks_v2.HttpMethod.POST, + "url": url, # The full url path that the task will be sent to. + } + } + if payload is not None: + if isinstance(payload, dict): + # Convert dict to JSON string + payload = json.dumps(payload) + # specify http content-type to application/json + task["http_request"]["headers"] = {"Content-type": "application/json"} + + # The API expects a payload of type bytes. + converted_payload = payload.encode() + + # Add the payload to the request. + task["http_request"]["body"] = converted_payload + + if in_seconds is not None: + # Convert "seconds from now" into an rfc3339 datetime string. + d = datetime.datetime.utcnow() + datetime.timedelta(seconds=in_seconds) + + # Create Timestamp protobuf. + timestamp = timestamp_pb2.Timestamp() + timestamp.FromDatetime(d) + + # Add the timestamp to the tasks. + task["schedule_time"] = timestamp + + if task_name is not None: + # Add the name to tasks. + task["name"] = client.task_path(project, location, queue, task_name) + + if deadline is not None: + # Add dispatch deadline for requests sent to the worker. + duration = duration_pb2.Duration() + duration.FromSeconds(deadline) + task["dispatch_deadline"] = duration + + # Use the client to build and send the task. + response = client.create_task(request={"parent": parent, "task": task}) + + print("Created task {}".format(response.name)) + # [END cloud_tasks_create_http_task] + return response + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=create_http_task.__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + parser.add_argument( + "--project", + help="Project of the queue to add the task to.", + required=True, + ) + + parser.add_argument( + "--queue", + help="ID (short name) of the queue to add the task to.", + required=True, + ) + + parser.add_argument( + "--location", + help="Location of the queue to add the task to.", + required=True, + ) + + parser.add_argument( + "--url", + help="The full url path that the request will be sent to.", + required=True, + ) + + parser.add_argument( + "--payload", help="Optional payload to attach to the push queue." + ) + + parser.add_argument( + "--in_seconds", + type=int, + help="The number of seconds from now to schedule task attempt.", + ) + + parser.add_argument("--task_name", help="Task name of the task to create") + args = parser.parse_args() + + create_http_task( + args.project, + args.queue, + args.location, + args.url, + args.payload, + args.in_seconds, + args.task_name, + ) diff --git a/cloud_tasks/snippets/create_http_task_test.py b/cloud_tasks/snippets/create_http_task_test.py new file mode 100644 index 000000000000..ce86c988b608 --- /dev/null +++ b/cloud_tasks/snippets/create_http_task_test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# Copyright 2022 Google, Inc. +# +# 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 + +from google.cloud import tasks_v2 +import pytest + +import create_http_task + +TEST_PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +TEST_LOCATION = os.getenv("TEST_QUEUE_LOCATION", "us-central1") +TEST_QUEUE_NAME = f"my-queue-{uuid.uuid4().hex}" + + +@pytest.fixture() +def test_queue(): + client = tasks_v2.CloudTasksClient() + parent = f"projects/{TEST_PROJECT_ID}/locations/{TEST_LOCATION}" + queue = { + # The fully qualified path to the queue + "name": client.queue_path(TEST_PROJECT_ID, TEST_LOCATION, TEST_QUEUE_NAME), + } + q = client.create_queue(request={"parent": parent, "queue": queue}) + + yield q + + client.delete_queue(request={"name": q.name}) + + +def test_create_http_task(test_queue): + url = "https://example.com/task_handler" + result = create_http_task.create_http_task( + TEST_PROJECT_ID, TEST_QUEUE_NAME, TEST_LOCATION, url + ) + assert TEST_QUEUE_NAME in result.name + + result = create_http_task.create_http_task( + TEST_PROJECT_ID, + TEST_QUEUE_NAME, + TEST_LOCATION, + url, + payload="hello", + in_seconds=180, + task_name=uuid.uuid4().hex, + deadline=900, + ) + assert TEST_QUEUE_NAME in result.name diff --git a/cloud_tasks/snippets/create_http_task_with_token.py b/cloud_tasks/snippets/create_http_task_with_token.py new file mode 100644 index 000000000000..eb98f758302b --- /dev/null +++ b/cloud_tasks/snippets/create_http_task_with_token.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# Copyright 2022 Google, Inc. +# +# 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. + +from __future__ import print_function + + +def create_http_task( + project, + queue, + location, + url, + service_account_email, + audience=None, + payload=None, +): + # [START cloud_tasks_create_http_task_with_token] + """Create a task for a given queue with an arbitrary payload.""" + + from google.cloud import tasks_v2 + + # Create a client. + client = tasks_v2.CloudTasksClient() + + # TODO(developer): Uncomment these lines and replace with your values. + # project = 'my-project-id' + # queue = 'my-queue' + # location = 'us-central1' + # url = 'https://example.com/task_handler?param=value' + # audience = 'https://example.com/task_handler' + # service_account_email = 'service-account@my-project-id.iam.gserviceaccount.com'; + # payload = 'hello' + + # Construct the fully qualified queue name. + parent = client.queue_path(project, location, queue) + + # Construct the request body. + task = { + "http_request": { # Specify the type of request. + "http_method": tasks_v2.HttpMethod.POST, + "url": url, # The full url path that the task will be sent to. + "oidc_token": { + "service_account_email": service_account_email, + "audience": audience, + }, + } + } + + if payload is not None: + # The API expects a payload of type bytes. + converted_payload = payload.encode() + + # Add the payload to the request. + task["http_request"]["body"] = converted_payload + + # Use the client to build and send the task. + response = client.create_task(request={"parent": parent, "task": task}) + + print("Created task {}".format(response.name)) + return response + + +# [END cloud_tasks_create_http_task_with_token] diff --git a/cloud_tasks/snippets/create_http_task_with_token_test.py b/cloud_tasks/snippets/create_http_task_with_token_test.py new file mode 100644 index 000000000000..39028881a83b --- /dev/null +++ b/cloud_tasks/snippets/create_http_task_with_token_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright 2022 Google, Inc. +# +# 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 + +from google.cloud import tasks_v2 +import pytest + +import create_http_task_with_token + +TEST_PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +TEST_LOCATION = os.getenv("TEST_QUEUE_LOCATION", "us-central1") +TEST_QUEUE_NAME = f"my-queue-{uuid.uuid4().hex}" +TEST_SERVICE_ACCOUNT = ( + "test-run-invoker@python-docs-samples-tests.iam.gserviceaccount.com" +) + + +@pytest.fixture() +def test_queue(): + client = tasks_v2.CloudTasksClient() + parent = f"projects/{TEST_PROJECT_ID}/locations/{TEST_LOCATION}" + queue = { + # The fully qualified path to the queue + "name": client.queue_path(TEST_PROJECT_ID, TEST_LOCATION, TEST_QUEUE_NAME), + } + q = client.create_queue(request={"parent": parent, "queue": queue}) + + yield q + + client.delete_queue(request={"name": q.name}) + + +def test_create_http_task_with_token(test_queue): + url = "https://example.com/task_handler" + result = create_http_task_with_token.create_http_task( + TEST_PROJECT_ID, TEST_QUEUE_NAME, TEST_LOCATION, url, TEST_SERVICE_ACCOUNT + ) + assert TEST_QUEUE_NAME in result.name diff --git a/cloud_tasks/snippets/requirements-test.txt b/cloud_tasks/snippets/requirements-test.txt new file mode 100644 index 000000000000..49780e035690 --- /dev/null +++ b/cloud_tasks/snippets/requirements-test.txt @@ -0,0 +1 @@ +pytest==7.2.0 diff --git a/cloud_tasks/snippets/requirements.txt b/cloud_tasks/snippets/requirements.txt new file mode 100644 index 000000000000..1bbf5163c064 --- /dev/null +++ b/cloud_tasks/snippets/requirements.txt @@ -0,0 +1 @@ +google-cloud-tasks==2.10.4 diff --git a/tasks/README.md b/tasks/README.md deleted file mode 100644 index 045b12d8e5f0..000000000000 --- a/tasks/README.md +++ /dev/null @@ -1,3 +0,0 @@ -These samples have been moved. - -https://github.com/googleapis/python-tasks/tree/main/samples