diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 8057a76..280fec1 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -54,4 +54,4 @@ jobs: - name: Report coverage results run: | coverage combine .coverage-results/.coverage* - coverage report --show-missing --fail-under=100 + coverage report --show-missing --fail-under=99 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bcd0522..e7ca613 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.6.0" + ".": "0.7.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c06c5..f75672b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## [0.7.0](https://github.com/googleapis/python-run/compare/v0.6.0...v0.7.0) (2023-01-20) + + +### Features + +* Adding support for encryption_key_revocation_action and encryption_key_shutdown_duration for RevisionTemplate and ExecutionTemplate ([bdb8baf](https://github.com/googleapis/python-run/commit/bdb8bafc7884624dea93082f1ef764768c9c13b6)) + + +### Bug Fixes + +* Add context manager return types ([bdb8baf](https://github.com/googleapis/python-run/commit/bdb8bafc7884624dea93082f1ef764768c9c13b6)) + + +### Documentation + +* Add documentation for enums ([bdb8baf](https://github.com/googleapis/python-run/commit/bdb8bafc7884624dea93082f1ef764768c9c13b6)) +* Documentation improvements, including clarification that v1 labels/annotations are rejected in v2 API ([bdb8baf](https://github.com/googleapis/python-run/commit/bdb8bafc7884624dea93082f1ef764768c9c13b6)) + ## [0.6.0](https://github.com/googleapis/python-run/compare/v0.5.0...v0.6.0) (2023-01-10) diff --git a/google/cloud/run/__init__.py b/google/cloud/run/__init__.py index 8155e18..287f245 100644 --- a/google/cloud/run/__init__.py +++ b/google/cloud/run/__init__.py @@ -98,6 +98,7 @@ ) from google.cloud.run_v2.types.vendor_settings import ( BinaryAuthorization, + EncryptionKeyRevocationAction, ExecutionEnvironment, IngressTraffic, RevisionScaling, @@ -172,6 +173,7 @@ "BinaryAuthorization", "RevisionScaling", "VpcAccess", + "EncryptionKeyRevocationAction", "ExecutionEnvironment", "IngressTraffic", ) diff --git a/google/cloud/run/gapic_version.py b/google/cloud/run/gapic_version.py index 06b4a76..e341813 100644 --- a/google/cloud/run/gapic_version.py +++ b/google/cloud/run/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.0" # {x-release-please-version} +__version__ = "0.7.0" # {x-release-please-version} diff --git a/google/cloud/run_v2/__init__.py b/google/cloud/run_v2/__init__.py index ba62b9f..5ce2b49 100644 --- a/google/cloud/run_v2/__init__.py +++ b/google/cloud/run_v2/__init__.py @@ -93,6 +93,7 @@ ) from .types.vendor_settings import ( BinaryAuthorization, + EncryptionKeyRevocationAction, ExecutionEnvironment, IngressTraffic, RevisionScaling, @@ -116,6 +117,7 @@ "DeleteJobRequest", "DeleteRevisionRequest", "DeleteServiceRequest", + "EncryptionKeyRevocationAction", "EnvVar", "EnvVarSource", "Execution", diff --git a/google/cloud/run_v2/gapic_version.py b/google/cloud/run_v2/gapic_version.py index 06b4a76..e341813 100644 --- a/google/cloud/run_v2/gapic_version.py +++ b/google/cloud/run_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.0" # {x-release-please-version} +__version__ = "0.7.0" # {x-release-please-version} diff --git a/google/cloud/run_v2/services/executions/async_client.py b/google/cloud/run_v2/services/executions/async_client.py index ec231e6..6555ecd 100644 --- a/google/cloud/run_v2/services/executions/async_client.py +++ b/google/cloud/run_v2/services/executions/async_client.py @@ -736,6 +736,66 @@ async def delete_operation( metadata=metadata, ) + async def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/run_v2/services/executions/client.py b/google/cloud/run_v2/services/executions/client.py index 098699c..7c5aaee 100644 --- a/google/cloud/run_v2/services/executions/client.py +++ b/google/cloud/run_v2/services/executions/client.py @@ -905,7 +905,7 @@ def sample_delete_execution(): # Done; return the response. return response - def __enter__(self): + def __enter__(self) -> "ExecutionsClient": return self def __exit__(self, type, value, traceback): @@ -1081,6 +1081,66 @@ def delete_operation( metadata=metadata, ) + def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/run_v2/services/executions/transports/base.py b/google/cloud/run_v2/services/executions/transports/base.py index 3d8005c..393f332 100644 --- a/google/cloud/run_v2/services/executions/transports/base.py +++ b/google/cloud/run_v2/services/executions/transports/base.py @@ -212,6 +212,15 @@ def delete_operation( ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: raise NotImplementedError() + @property + def wait_operation( + self, + ) -> Callable[ + [operations_pb2.WaitOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/executions/transports/grpc.py b/google/cloud/run_v2/services/executions/transports/grpc.py index cb26b6a..f3aec2b 100644 --- a/google/cloud/run_v2/services/executions/transports/grpc.py +++ b/google/cloud/run_v2/services/executions/transports/grpc.py @@ -343,6 +343,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py b/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py index 41fd7a9..15672f6 100644 --- a/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py @@ -352,6 +352,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/executions/transports/rest.py b/google/cloud/run_v2/services/executions/transports/rest.py index 8455972..9c2d911 100644 --- a/google/cloud/run_v2/services/executions/transports/rest.py +++ b/google/cloud/run_v2/services/executions/transports/rest.py @@ -239,6 +239,29 @@ def post_list_operations( """ return response + def pre_wait_operation( + self, + request: operations_pb2.WaitOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for wait_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_wait_operation( + self, response: operations_pb2.WaitOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for wait_operation + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class ExecutionsRestStub: @@ -365,6 +388,13 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: "uri": "/v2/{name=projects/*/locations/*}/operations", }, ], + "google.longrunning.Operations.WaitOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ], } rest_transport = operations_v1.OperationsRestTransport( @@ -878,6 +908,76 @@ def __call__( resp = self._interceptor.post_list_operations(resp) return resp + @property + def wait_operation(self): + return self._WaitOperation(self._session, self._host, self._interceptor) # type: ignore + + class _WaitOperation(ExecutionsRestStub): + def __call__( + self, + request: operations_pb2.WaitOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the wait operation method over HTTP. + + Args: + request (operations_pb2.WaitOperationRequest): + The request object for WaitOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from WaitOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ] + + request, metadata = self._interceptor.pre_wait_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + body = json.loads(json.dumps(transcoded_request["body"])) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_wait_operation(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/jobs/async_client.py b/google/cloud/run_v2/services/jobs/async_client.py index 4529c23..622c6cf 100644 --- a/google/cloud/run_v2/services/jobs/async_client.py +++ b/google/cloud/run_v2/services/jobs/async_client.py @@ -310,9 +310,8 @@ async def sample_create_job(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -429,9 +428,8 @@ async def sample_get_job(): Returns: google.cloud.run_v2.types.Job: Job represents the configuration of a - single job. A job an immutable resource - that references a container image which - is run to completion. + single job, which references a container + image that is run to completion. """ # Create or coerce a protobuf request object. @@ -656,9 +654,8 @@ async def sample_update_job(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -776,9 +773,8 @@ async def sample_delete_job(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -1489,6 +1485,66 @@ async def delete_operation( metadata=metadata, ) + async def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/run_v2/services/jobs/client.py b/google/cloud/run_v2/services/jobs/client.py index 9665049..0f5bd63 100644 --- a/google/cloud/run_v2/services/jobs/client.py +++ b/google/cloud/run_v2/services/jobs/client.py @@ -646,9 +646,8 @@ def sample_create_job(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -765,9 +764,8 @@ def sample_get_job(): Returns: google.cloud.run_v2.types.Job: Job represents the configuration of a - single job. A job an immutable resource - that references a container image which - is run to completion. + single job, which references a container + image that is run to completion. """ # Create or coerce a protobuf request object. @@ -992,9 +990,8 @@ def sample_update_job(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -1112,9 +1109,8 @@ def sample_delete_job(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource - that references a container image which is run to - completion. + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job, which references a + container image that is run to completion. """ # Create or coerce a protobuf request object. @@ -1659,7 +1655,7 @@ def sample_test_iam_permissions(): # Done; return the response. return response - def __enter__(self): + def __enter__(self) -> "JobsClient": return self def __exit__(self, type, value, traceback): @@ -1835,6 +1831,66 @@ def delete_operation( metadata=metadata, ) + def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/run_v2/services/jobs/transports/base.py b/google/cloud/run_v2/services/jobs/transports/base.py index a8a90fa..20a22e4 100644 --- a/google/cloud/run_v2/services/jobs/transports/base.py +++ b/google/cloud/run_v2/services/jobs/transports/base.py @@ -296,6 +296,15 @@ def delete_operation( ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: raise NotImplementedError() + @property + def wait_operation( + self, + ) -> Callable[ + [operations_pb2.WaitOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/jobs/transports/grpc.py b/google/cloud/run_v2/services/jobs/transports/grpc.py index aaaff2c..c36c273 100644 --- a/google/cloud/run_v2/services/jobs/transports/grpc.py +++ b/google/cloud/run_v2/services/jobs/transports/grpc.py @@ -503,6 +503,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py b/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py index dfbeac2..a5ac42c 100644 --- a/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py @@ -514,6 +514,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/jobs/transports/rest.py b/google/cloud/run_v2/services/jobs/transports/rest.py index 494ab09..9e318ce 100644 --- a/google/cloud/run_v2/services/jobs/transports/rest.py +++ b/google/cloud/run_v2/services/jobs/transports/rest.py @@ -410,6 +410,29 @@ def post_list_operations( """ return response + def pre_wait_operation( + self, + request: operations_pb2.WaitOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for wait_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_wait_operation( + self, response: operations_pb2.WaitOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for wait_operation + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class JobsRestStub: @@ -536,6 +559,13 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: "uri": "/v2/{name=projects/*/locations/*}/operations", }, ], + "google.longrunning.Operations.WaitOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ], } rest_transport = operations_v1.OperationsRestTransport( @@ -939,9 +969,8 @@ def __call__( Returns: ~.job.Job: Job represents the configuration of a - single job. A job an immutable resource - that references a container image which - is run to completion. + single job, which references a container + image that is run to completion. """ @@ -1807,6 +1836,76 @@ def __call__( resp = self._interceptor.post_list_operations(resp) return resp + @property + def wait_operation(self): + return self._WaitOperation(self._session, self._host, self._interceptor) # type: ignore + + class _WaitOperation(JobsRestStub): + def __call__( + self, + request: operations_pb2.WaitOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the wait operation method over HTTP. + + Args: + request (operations_pb2.WaitOperationRequest): + The request object for WaitOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from WaitOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ] + + request, metadata = self._interceptor.pre_wait_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + body = json.loads(json.dumps(transcoded_request["body"])) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_wait_operation(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/revisions/async_client.py b/google/cloud/run_v2/services/revisions/async_client.py index d0715c9..d693522 100644 --- a/google/cloud/run_v2/services/revisions/async_client.py +++ b/google/cloud/run_v2/services/revisions/async_client.py @@ -734,6 +734,66 @@ async def delete_operation( metadata=metadata, ) + async def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/run_v2/services/revisions/client.py b/google/cloud/run_v2/services/revisions/client.py index 8ac806f..a696742 100644 --- a/google/cloud/run_v2/services/revisions/client.py +++ b/google/cloud/run_v2/services/revisions/client.py @@ -927,7 +927,7 @@ def sample_delete_revision(): # Done; return the response. return response - def __enter__(self): + def __enter__(self) -> "RevisionsClient": return self def __exit__(self, type, value, traceback): @@ -1103,6 +1103,66 @@ def delete_operation( metadata=metadata, ) + def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/run_v2/services/revisions/transports/base.py b/google/cloud/run_v2/services/revisions/transports/base.py index c1deb55..0c2ef8c 100644 --- a/google/cloud/run_v2/services/revisions/transports/base.py +++ b/google/cloud/run_v2/services/revisions/transports/base.py @@ -211,6 +211,15 @@ def delete_operation( ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: raise NotImplementedError() + @property + def wait_operation( + self, + ) -> Callable[ + [operations_pb2.WaitOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/revisions/transports/grpc.py b/google/cloud/run_v2/services/revisions/transports/grpc.py index 50d4179..0982baa 100644 --- a/google/cloud/run_v2/services/revisions/transports/grpc.py +++ b/google/cloud/run_v2/services/revisions/transports/grpc.py @@ -344,6 +344,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py b/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py index 55ee1fd..03acd16 100644 --- a/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py @@ -353,6 +353,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/revisions/transports/rest.py b/google/cloud/run_v2/services/revisions/transports/rest.py index 9978220..67a4580 100644 --- a/google/cloud/run_v2/services/revisions/transports/rest.py +++ b/google/cloud/run_v2/services/revisions/transports/rest.py @@ -237,6 +237,29 @@ def post_list_operations( """ return response + def pre_wait_operation( + self, + request: operations_pb2.WaitOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for wait_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Revisions server. + """ + return request, metadata + + def post_wait_operation( + self, response: operations_pb2.WaitOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for wait_operation + + Override in a subclass to manipulate the response + after it is returned by the Revisions server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class RevisionsRestStub: @@ -363,6 +386,13 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: "uri": "/v2/{name=projects/*/locations/*}/operations", }, ], + "google.longrunning.Operations.WaitOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ], } rest_transport = operations_v1.OperationsRestTransport( @@ -877,6 +907,76 @@ def __call__( resp = self._interceptor.post_list_operations(resp) return resp + @property + def wait_operation(self): + return self._WaitOperation(self._session, self._host, self._interceptor) # type: ignore + + class _WaitOperation(RevisionsRestStub): + def __call__( + self, + request: operations_pb2.WaitOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the wait operation method over HTTP. + + Args: + request (operations_pb2.WaitOperationRequest): + The request object for WaitOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from WaitOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ] + + request, metadata = self._interceptor.pre_wait_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + body = json.loads(json.dumps(transcoded_request["body"])) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_wait_operation(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/services/async_client.py b/google/cloud/run_v2/services/services/async_client.py index 79f78ed..30caa6a 100644 --- a/google/cloud/run_v2/services/services/async_client.py +++ b/google/cloud/run_v2/services/services/async_client.py @@ -544,8 +544,8 @@ async def sample_list_services(): parent (:class:`str`): Required. The location and project to list resources on. Location must be a - valid GCP region, and cannot be the "-" - wildcard. Format: + valid Google Cloud region, and cannot be + the "-" wildcard. Format: projects/{project}/locations/{location}, where {project} can be project id or number. @@ -1412,6 +1412,66 @@ async def delete_operation( metadata=metadata, ) + async def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/run_v2/services/services/client.py b/google/cloud/run_v2/services/services/client.py index 8da37ba..2bf9ca8 100644 --- a/google/cloud/run_v2/services/services/client.py +++ b/google/cloud/run_v2/services/services/client.py @@ -885,8 +885,8 @@ def sample_list_services(): parent (str): Required. The location and project to list resources on. Location must be a - valid GCP region, and cannot be the "-" - wildcard. Format: + valid Google Cloud region, and cannot be + the "-" wildcard. Format: projects/{project}/locations/{location}, where {project} can be project id or number. @@ -1600,7 +1600,7 @@ def sample_test_iam_permissions(): # Done; return the response. return response - def __enter__(self): + def __enter__(self) -> "ServicesClient": return self def __exit__(self, type, value, traceback): @@ -1776,6 +1776,66 @@ def delete_operation( metadata=metadata, ) + def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/run_v2/services/services/transports/base.py b/google/cloud/run_v2/services/services/transports/base.py index 2010b3a..259845b 100644 --- a/google/cloud/run_v2/services/services/transports/base.py +++ b/google/cloud/run_v2/services/services/transports/base.py @@ -302,6 +302,15 @@ def delete_operation( ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: raise NotImplementedError() + @property + def wait_operation( + self, + ) -> Callable[ + [operations_pb2.WaitOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/services/transports/grpc.py b/google/cloud/run_v2/services/services/transports/grpc.py index 47cddd6..1216e66 100644 --- a/google/cloud/run_v2/services/services/transports/grpc.py +++ b/google/cloud/run_v2/services/services/transports/grpc.py @@ -486,6 +486,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/services/transports/grpc_asyncio.py b/google/cloud/run_v2/services/services/transports/grpc_asyncio.py index 848c7f8..b8e66b5 100644 --- a/google/cloud/run_v2/services/services/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/services/transports/grpc_asyncio.py @@ -499,6 +499,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/services/transports/rest.py b/google/cloud/run_v2/services/services/transports/rest.py index 90605af..eb30b71 100644 --- a/google/cloud/run_v2/services/services/transports/rest.py +++ b/google/cloud/run_v2/services/services/transports/rest.py @@ -387,6 +387,29 @@ def post_list_operations( """ return response + def pre_wait_operation( + self, + request: operations_pb2.WaitOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for wait_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Services server. + """ + return request, metadata + + def post_wait_operation( + self, response: operations_pb2.WaitOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for wait_operation + + Override in a subclass to manipulate the response + after it is returned by the Services server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class ServicesRestStub: @@ -513,6 +536,13 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: "uri": "/v2/{name=projects/*/locations/*}/operations", }, ], + "google.longrunning.Operations.WaitOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ], } rest_transport = operations_v1.OperationsRestTransport( @@ -1693,6 +1723,76 @@ def __call__( resp = self._interceptor.post_list_operations(resp) return resp + @property + def wait_operation(self): + return self._WaitOperation(self._session, self._host, self._interceptor) # type: ignore + + class _WaitOperation(ServicesRestStub): + def __call__( + self, + request: operations_pb2.WaitOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the wait operation method over HTTP. + + Args: + request (operations_pb2.WaitOperationRequest): + The request object for WaitOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from WaitOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ] + + request, metadata = self._interceptor.pre_wait_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + body = json.loads(json.dumps(transcoded_request["body"])) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_wait_operation(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/tasks/async_client.py b/google/cloud/run_v2/services/tasks/async_client.py index 969be2c..1772fda 100644 --- a/google/cloud/run_v2/services/tasks/async_client.py +++ b/google/cloud/run_v2/services/tasks/async_client.py @@ -607,6 +607,66 @@ async def delete_operation( metadata=metadata, ) + async def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/run_v2/services/tasks/client.py b/google/cloud/run_v2/services/tasks/client.py index e410c56..76b7e5f 100644 --- a/google/cloud/run_v2/services/tasks/client.py +++ b/google/cloud/run_v2/services/tasks/client.py @@ -804,7 +804,7 @@ def sample_list_tasks(): # Done; return the response. return response - def __enter__(self): + def __enter__(self) -> "TasksClient": return self def __exit__(self, type, value, traceback): @@ -980,6 +980,66 @@ def delete_operation( metadata=metadata, ) + def wait_operation( + self, + request: Optional[operations_pb2.WaitOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Waits until the specified long-running operation is done or reaches at most + a specified timeout, returning the latest state. + + If the operation is already done, the latest state is immediately returned. + If the timeout specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + timeout is used. If the server does not support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.WaitOperationRequest`): + The request object. Request message for + `WaitOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.WaitOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.wait_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/run_v2/services/tasks/transports/base.py b/google/cloud/run_v2/services/tasks/transports/base.py index b7034c2..8f15ec5 100644 --- a/google/cloud/run_v2/services/tasks/transports/base.py +++ b/google/cloud/run_v2/services/tasks/transports/base.py @@ -187,6 +187,15 @@ def delete_operation( ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: raise NotImplementedError() + @property + def wait_operation( + self, + ) -> Callable[ + [operations_pb2.WaitOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/tasks/transports/grpc.py b/google/cloud/run_v2/services/tasks/transports/grpc.py index e38f42b..91d2e7c 100644 --- a/google/cloud/run_v2/services/tasks/transports/grpc.py +++ b/google/cloud/run_v2/services/tasks/transports/grpc.py @@ -298,6 +298,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py b/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py index 43c85e6..58b1f42 100644 --- a/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py @@ -303,6 +303,23 @@ def delete_operation( ) return self._stubs["delete_operation"] + @property + def wait_operation( + self, + ) -> Callable[[operations_pb2.WaitOperationRequest], None]: + r"""Return a callable for the wait_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["wait_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/WaitOperation", + request_serializer=operations_pb2.WaitOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["wait_operation"] + @property def get_operation( self, diff --git a/google/cloud/run_v2/services/tasks/transports/rest.py b/google/cloud/run_v2/services/tasks/transports/rest.py index 7c339f3..e3a54b4 100644 --- a/google/cloud/run_v2/services/tasks/transports/rest.py +++ b/google/cloud/run_v2/services/tasks/transports/rest.py @@ -196,6 +196,29 @@ def post_list_operations( """ return response + def pre_wait_operation( + self, + request: operations_pb2.WaitOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for wait_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_wait_operation( + self, response: operations_pb2.WaitOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for wait_operation + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class TasksRestStub: @@ -682,6 +705,76 @@ def __call__( resp = self._interceptor.post_list_operations(resp) return resp + @property + def wait_operation(self): + return self._WaitOperation(self._session, self._host, self._interceptor) # type: ignore + + class _WaitOperation(TasksRestStub): + def __call__( + self, + request: operations_pb2.WaitOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the wait operation method over HTTP. + + Args: + request (operations_pb2.WaitOperationRequest): + The request object for WaitOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from WaitOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:wait", + "body": "*", + }, + ] + + request, metadata = self._interceptor.pre_wait_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + body = json.loads(json.dumps(transcoded_request["body"])) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_wait_operation(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/types/__init__.py b/google/cloud/run_v2/types/__init__.py index 6dd1c06..c726327 100644 --- a/google/cloud/run_v2/types/__init__.py +++ b/google/cloud/run_v2/types/__init__.py @@ -83,6 +83,7 @@ ) from .vendor_settings import ( BinaryAuthorization, + EncryptionKeyRevocationAction, ExecutionEnvironment, IngressTraffic, RevisionScaling, @@ -147,6 +148,7 @@ "BinaryAuthorization", "RevisionScaling", "VpcAccess", + "EncryptionKeyRevocationAction", "ExecutionEnvironment", "IngressTraffic", ) diff --git a/google/cloud/run_v2/types/condition.py b/google/cloud/run_v2/types/condition.py index 4285975..38bff3f 100644 --- a/google/cloud/run_v2/types/condition.py +++ b/google/cloud/run_v2/types/condition.py @@ -71,7 +71,25 @@ class Condition(proto.Message): """ class State(proto.Enum): - r"""Represents the possible Condition states.""" + r"""Represents the possible Condition states. + + Values: + STATE_UNSPECIFIED (0): + The default value. This value is used if the + state is omitted. + CONDITION_PENDING (1): + Transient state: Reconciliation has not + started yet. + CONDITION_RECONCILING (2): + Transient state: reconciliation is still in + progress. + CONDITION_FAILED (3): + Terminal state: Reconciliation did not + succeed. + CONDITION_SUCCEEDED (4): + Terminal state: Reconciliation completed + successfully. + """ STATE_UNSPECIFIED = 0 CONDITION_PENDING = 1 CONDITION_RECONCILING = 2 @@ -79,14 +97,63 @@ class State(proto.Enum): CONDITION_SUCCEEDED = 4 class Severity(proto.Enum): - r"""Represents the severity of the condition failures.""" + r"""Represents the severity of the condition failures. + + Values: + SEVERITY_UNSPECIFIED (0): + Unspecified severity + ERROR (1): + Error severity. + WARNING (2): + Warning severity. + INFO (3): + Info severity. + """ SEVERITY_UNSPECIFIED = 0 ERROR = 1 WARNING = 2 INFO = 3 class CommonReason(proto.Enum): - r"""Reasons common to all types of conditions.""" + r"""Reasons common to all types of conditions. + + Values: + COMMON_REASON_UNDEFINED (0): + Default value. + UNKNOWN (1): + Reason unknown. Further details will be in + message. + REVISION_FAILED (3): + Revision creation process failed. + PROGRESS_DEADLINE_EXCEEDED (4): + Timed out waiting for completion. + CONTAINER_MISSING (6): + The container image path is incorrect. + CONTAINER_PERMISSION_DENIED (7): + Insufficient permissions on the container + image. + CONTAINER_IMAGE_UNAUTHORIZED (8): + Container image is not authorized by policy. + CONTAINER_IMAGE_AUTHORIZATION_CHECK_FAILED (9): + Container image policy authorization check + failed. + ENCRYPTION_KEY_PERMISSION_DENIED (10): + Insufficient permissions on encryption key. + ENCRYPTION_KEY_CHECK_FAILED (11): + Permission check on encryption key failed. + SECRETS_ACCESS_CHECK_FAILED (12): + At least one Access check on secrets failed. + WAITING_FOR_OPERATION (13): + Waiting for operation to complete. + IMMEDIATE_RETRY (14): + System will retry immediately. + POSTPONED_RETRY (15): + System will retry later; current attempt + failed. + INTERNAL (16): + An internal error occurred. Further + information may be in the message. + """ COMMON_REASON_UNDEFINED = 0 UNKNOWN = 1 REVISION_FAILED = 3 @@ -104,7 +171,48 @@ class CommonReason(proto.Enum): INTERNAL = 16 class RevisionReason(proto.Enum): - r"""Reasons specific to Revision resource.""" + r"""Reasons specific to Revision resource. + + Values: + REVISION_REASON_UNDEFINED (0): + Default value. + PENDING (1): + Revision in Pending state. + RESERVE (2): + Revision is in Reserve state. + RETIRED (3): + Revision is Retired. + RETIRING (4): + Revision is being retired. + RECREATING (5): + Revision is being recreated. + HEALTH_CHECK_CONTAINER_ERROR (6): + There was a health check error. + CUSTOMIZED_PATH_RESPONSE_PENDING (7): + Health check failed due to user error from + customized path of the container. System will + retry. + MIN_INSTANCES_NOT_PROVISIONED (8): + A revision with min_instance_count > 0 was created and is + reserved, but it was not configured to serve traffic, so + it's not live. This can also happen momentarily during + traffic migration. + ACTIVE_REVISION_LIMIT_REACHED (9): + The maximum allowed number of active + revisions has been reached. + NO_DEPLOYMENT (10): + There was no deployment defined. + This value is no longer used, but Services + created in older versions of the API might + contain this value. + HEALTH_CHECK_SKIPPED (11): + A revision's container has no port specified + since the revision is of a manually scaled + service with 0 instance count + MIN_INSTANCES_WARMING (12): + A revision with min_instance_count > 0 was created and is + waiting for enough instances to begin a traffic migration. + """ REVISION_REASON_UNDEFINED = 0 PENDING = 1 RESERVE = 2 @@ -117,9 +225,24 @@ class RevisionReason(proto.Enum): ACTIVE_REVISION_LIMIT_REACHED = 9 NO_DEPLOYMENT = 10 HEALTH_CHECK_SKIPPED = 11 + MIN_INSTANCES_WARMING = 12 class ExecutionReason(proto.Enum): - r"""Reasons specific to Execution resource.""" + r"""Reasons specific to Execution resource. + + Values: + EXECUTION_REASON_UNDEFINED (0): + Default value. + JOB_STATUS_SERVICE_POLLING_ERROR (1): + Internal system error getting execution + status. System will retry. + NON_ZERO_EXIT_CODE (2): + A task reached its retry limit and the last + attempt failed due to the user container exiting + with a non-zero exit code. + CANCELLED (3): + The execution was cancelled by users. + """ EXECUTION_REASON_UNDEFINED = 0 JOB_STATUS_SERVICE_POLLING_ERROR = 1 NON_ZERO_EXIT_CODE = 2 diff --git a/google/cloud/run_v2/types/execution.py b/google/cloud/run_v2/types/execution.py index 8d0377d..2c69312 100644 --- a/google/cloud/run_v2/types/execution.py +++ b/google/cloud/run_v2/types/execution.py @@ -177,10 +177,6 @@ class Execution(proto.Message): https://cloud.google.com/resource-manager/docs/creating-managing-labels or https://cloud.google.com/run/docs/configuring/labels - Cloud Run will populate some labels with - 'run.googleapis.com' or 'serving.knative.dev' - namespaces. Those labels are read-only, and user - changes will not be preserved. annotations (MutableMapping[str, str]): KRM-style annotations for the resource. create_time (google.protobuf.timestamp_pb2.Timestamp): @@ -258,6 +254,15 @@ class Execution(proto.Message): failed_count (int): Output only. The number of tasks which reached phase Failed. + cancelled_count (int): + Output only. The number of tasks which + reached phase Cancelled. + retried_count (int): + Output only. The number of tasks which have + retried at least once. + log_uri (str): + Output only. URI where logs for this + execution can be found in Cloud Console. etag (str): Output only. A system-generated fingerprint for this version of the resource. May be used to @@ -363,6 +368,18 @@ class Execution(proto.Message): proto.INT32, number=21, ) + cancelled_count: int = proto.Field( + proto.INT32, + number=24, + ) + retried_count: int = proto.Field( + proto.INT32, + number=25, + ) + log_uri: str = proto.Field( + proto.STRING, + number=26, + ) etag: str = proto.Field( proto.STRING, number=99, diff --git a/google/cloud/run_v2/types/execution_template.py b/google/cloud/run_v2/types/execution_template.py index 83fd896..746cbb3 100644 --- a/google/cloud/run_v2/types/execution_template.py +++ b/google/cloud/run_v2/types/execution_template.py @@ -34,8 +34,22 @@ class ExecutionTemplate(proto.Message): Attributes: labels (MutableMapping[str, str]): KRM-style labels for the resource. + + .. raw:: html + +
Cloud Run API v2 does not support labels with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system labels in v1 now have a + corresponding field in v2 ExecutionTemplate. annotations (MutableMapping[str, str]): KRM-style annotations for the resource. + + .. raw:: html + +
Cloud Run API v2 does not support annotations with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system annotations in v1 now + have a corresponding field in v2 ExecutionTemplate. parallelism (int): Specifies the maximum desired number of tasks the execution should run at given time. Must be <= task_count. When the diff --git a/google/cloud/run_v2/types/job.py b/google/cloud/run_v2/types/job.py index 0ea268b..248a89c 100644 --- a/google/cloud/run_v2/types/job.py +++ b/google/cloud/run_v2/types/job.py @@ -258,9 +258,8 @@ class RunJobRequest(proto.Message): class Job(proto.Message): - r"""Job represents the configuration of a single job. A job an - immutable resource that references a container image which is - run to completion. + r"""Job represents the configuration of a single job, which + references a container image that is run to completion. Attributes: name (str): @@ -277,30 +276,36 @@ class Job(proto.Message): increases every time the user modifies the desired state. labels (MutableMapping[str, str]): - KRM-style labels for the resource. - User-provided labels are shared with Google's - billing system, so they can be used to filter, - or break down billing charges by team, - component, environment, state, etc. For more - information, visit + KRM-style labels for the resource. User-provided labels are + shared with Google's billing system, so they can be used to + filter, or break down billing charges by team, component, + environment, state, etc. For more information, visit https://cloud.google.com/resource-manager/docs/creating-managing-labels - or - https://cloud.google.com/run/docs/configuring/labels - Cloud Run will populate some labels with - 'run.googleapis.com' or 'serving.knative.dev' - namespaces. Those labels are read-only, and user - changes will not be preserved. + or https://cloud.google.com/run/docs/configuring/labels + + .. raw:: html + +
Cloud Run API v2 does not support labels with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system labels in v1 now have a + corresponding field in v2 Job. annotations (MutableMapping[str, str]): - KRM-style annotations for the resource. - Unstructured key value map that may be set by - external tools to store and arbitrary metadata. - They are not queryable and should be preserved - when modifying objects. Cloud Run will populate - some annotations using 'run.googleapis.com' or - 'serving.knative.dev' namespaces. This field - follows Kubernetes annotations' namespacing, - limits, and rules. More info: - https://kubernetes.io/docs/user-guide/annotations + KRM-style annotations for the resource. Unstructured key + value map that may be set by external tools to store and + arbitrary metadata. They are not queryable and should be + preserved when modifying objects. + + .. raw:: html + +
Cloud Run API v2 does not support annotations with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system annotations in v1 now + have a corresponding field in v2 Job. + + .. raw:: html + +
This field follows Kubernetes annotations' namespacing, limits, and + rules. More info: https://kubernetes.io/docs/user-guide/annotations create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The creation time. update_time (google.protobuf.timestamp_pb2.Timestamp): diff --git a/google/cloud/run_v2/types/k8s_min.py b/google/cloud/run_v2/types/k8s_min.py index 43ed90c..1d5271f 100644 --- a/google/cloud/run_v2/types/k8s_min.py +++ b/google/cloud/run_v2/types/k8s_min.py @@ -49,11 +49,12 @@ class Container(proto.Message): Attributes: name (str): - Name of the container specified as a DNS_LABEL. + Name of the container specified as a DNS_LABEL (RFC 1123). image (str): - Required. URL of the Container image in - Google Container Registry or Google Artifact - Registry. More info: + Required. Name of the container image in + Dockerhub, Google Artifact Registry, or Google + Container Registry. If the host is not provided, + Dockerhub is assumed. More info: https://kubernetes.io/docs/concepts/containers/images command (MutableSequence[str]): Entrypoint array. Not executed within a shell. The docker @@ -494,7 +495,10 @@ class VersionToPath(proto.Message): class CloudSqlInstance(proto.Message): - r"""Represents a specific Cloud SQL instance. + r"""Represents a set of Cloud SQL instances. Each one will be available + under /cloudsql/[instance]. Visit + https://cloud.google.com/sql/docs/mysql/connect-run for more + information on how to connect Cloud SQL and Cloud Run. Attributes: instances (MutableSequence[str]): diff --git a/google/cloud/run_v2/types/revision.py b/google/cloud/run_v2/types/revision.py index 64ad2b7..1585751 100644 --- a/google/cloud/run_v2/types/revision.py +++ b/google/cloud/run_v2/types/revision.py @@ -178,10 +178,6 @@ class Revision(proto.Message): https://cloud.google.com/resource-manager/docs/creating-managing-labels or https://cloud.google.com/run/docs/configuring/labels - Cloud Run will populate some labels with - 'run.googleapis.com' or 'serving.knative.dev' - namespaces. Those labels are read-only, and user - changes will not be preserved. annotations (MutableMapping[str, str]): KRM-style annotations for the resource. create_time (google.protobuf.timestamp_pb2.Timestamp): @@ -237,6 +233,13 @@ class Revision(proto.Message): key (CMEK) to use to encrypt this container image. For more information, go to https://cloud.google.com/run/docs/securing/using-cmek + encryption_key_revocation_action (google.cloud.run_v2.types.EncryptionKeyRevocationAction): + The action to take if the encryption key is + revoked. + encryption_key_shutdown_duration (google.protobuf.duration_pb2.Duration): + If encryption_key_revocation_action is SHUTDOWN, the + duration before shutting down all instances. The minimum + increment is 1 hour. reconciling (bool): Output only. Indicates whether the resource's reconciliation is still in progress. See comments in @@ -354,6 +357,18 @@ class Revision(proto.Message): proto.STRING, number=21, ) + encryption_key_revocation_action: vendor_settings.EncryptionKeyRevocationAction = ( + proto.Field( + proto.ENUM, + number=23, + enum=vendor_settings.EncryptionKeyRevocationAction, + ) + ) + encryption_key_shutdown_duration: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=24, + message=duration_pb2.Duration, + ) reconciling: bool = proto.Field( proto.BOOL, number=30, diff --git a/google/cloud/run_v2/types/revision_template.py b/google/cloud/run_v2/types/revision_template.py index e939e52..bfb53a4 100644 --- a/google/cloud/run_v2/types/revision_template.py +++ b/google/cloud/run_v2/types/revision_template.py @@ -39,8 +39,22 @@ class RevisionTemplate(proto.Message): generated based on the Service name. labels (MutableMapping[str, str]): KRM-style labels for the resource. + + .. raw:: html + +
Cloud Run API v2 does not support labels with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system labels in v1 now have a + corresponding field in v2 RevisionTemplate. annotations (MutableMapping[str, str]): KRM-style annotations for the resource. + + .. raw:: html + +
Cloud Run API v2 does not support annotations with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system annotations in v1 now + have a corresponding field in v2 RevisionTemplate. scaling (google.cloud.run_v2.types.RevisionScaling): Scaling settings for this Revision. vpc_access (google.cloud.run_v2.types.VpcAccess): diff --git a/google/cloud/run_v2/types/service.py b/google/cloud/run_v2/types/service.py index 2f0d3e4..d791494 100644 --- a/google/cloud/run_v2/types/service.py +++ b/google/cloud/run_v2/types/service.py @@ -122,10 +122,10 @@ class ListServicesRequest(proto.Message): Attributes: parent (str): Required. The location and project to list - resources on. Location must be a valid GCP - region, and cannot be the "-" wildcard. Format: - projects/{project}/locations/{location}, where - {project} can be project id or number. + resources on. Location must be a valid Google + Cloud region, and cannot be the "-" wildcard. + Format: projects/{project}/locations/{location}, + where {project} can be project id or number. page_size (int): Maximum number of Services to return in this call. @@ -263,30 +263,37 @@ class Service(proto.Message): its JSON representation will be a ``string`` instead of an ``integer``. labels (MutableMapping[str, str]): - Map of string keys and values that can be - used to organize and categorize objects. - User-provided labels are shared with Google's - billing system, so they can be used to filter, - or break down billing charges by team, - component, environment, state, etc. For more - information, visit + Map of string keys and values that can be used to organize + and categorize objects. User-provided labels are shared with + Google's billing system, so they can be used to filter, or + break down billing charges by team, component, environment, + state, etc. For more information, visit https://cloud.google.com/resource-manager/docs/creating-managing-labels - or - https://cloud.google.com/run/docs/configuring/labels - Cloud Run will populate some labels with - 'run.googleapis.com' or 'serving.knative.dev' - namespaces. Those labels are read-only, and user - changes will not be preserved. + or https://cloud.google.com/run/docs/configuring/labels + + .. raw:: html + +
Cloud Run API v2 does not support labels with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system labels in v1 now have a + corresponding field in v2 Service. annotations (MutableMapping[str, str]): - Unstructured key value map that may be set by - external tools to store and arbitrary metadata. - They are not queryable and should be preserved - when modifying objects. Cloud Run will populate - some annotations using 'run.googleapis.com' or - 'serving.knative.dev' namespaces. This field - follows Kubernetes annotations' namespacing, - limits, and rules. More info: - https://kubernetes.io/docs/user-guide/annotations + Unstructured key value map that may be set by external tools + to store and arbitrary metadata. They are not queryable and + should be preserved when modifying objects. + + .. raw:: html + +
Cloud Run API v2 does not support annotations with `run.googleapis.com`, + `cloud.googleapis.com`, `serving.knative.dev`, or `autoscaling.knative.dev` + namespaces, and they will be rejected. All system annotations in v1 now + have a corresponding field in v2 Service. + + .. raw:: html + +
This field follows Kubernetes + annotations' namespacing, limits, and rules. More info: + https://kubernetes.io/docs/user-guide/annotations create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The creation time. update_time (google.protobuf.timestamp_pb2.Timestamp): diff --git a/google/cloud/run_v2/types/task.py b/google/cloud/run_v2/types/task.py index fce97d5..1643483 100644 --- a/google/cloud/run_v2/types/task.py +++ b/google/cloud/run_v2/types/task.py @@ -141,10 +141,6 @@ class Task(proto.Message): https://cloud.google.com/resource-manager/docs/creating-managing-labels or https://cloud.google.com/run/docs/configuring/labels - Cloud Run will populate some labels with - 'run.googleapis.com' or 'serving.knative.dev' - namespaces. Those labels are read-only, and user - changes will not be preserved. annotations (MutableMapping[str, str]): KRM-style annotations for the resource. create_time (google.protobuf.timestamp_pb2.Timestamp): @@ -236,6 +232,9 @@ class Task(proto.Message): Output only. VPC Access configuration to use for this Task. For more information, visit https://cloud.google.com/run/docs/configuring/connecting-vpc. + log_uri (str): + Output only. URI where logs for this + execution can be found in Cloud Console. etag (str): Output only. A system-generated fingerprint for this version of the resource. May be used to @@ -365,6 +364,10 @@ class Task(proto.Message): number=29, message=vendor_settings.VpcAccess, ) + log_uri: str = proto.Field( + proto.STRING, + number=32, + ) etag: str = proto.Field( proto.STRING, number=99, diff --git a/google/cloud/run_v2/types/traffic_target.py b/google/cloud/run_v2/types/traffic_target.py index 12234b4..d5267aa 100644 --- a/google/cloud/run_v2/types/traffic_target.py +++ b/google/cloud/run_v2/types/traffic_target.py @@ -28,7 +28,17 @@ class TrafficTargetAllocationType(proto.Enum): - r"""The type of instance allocation.""" + r"""The type of instance allocation. + + Values: + TRAFFIC_TARGET_ALLOCATION_TYPE_UNSPECIFIED (0): + Unspecified instance allocation type. + TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST (1): + Allocates instances to the Service's latest + ready Revision. + TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION (2): + Allocates instances to a Revision by name. + """ TRAFFIC_TARGET_ALLOCATION_TYPE_UNSPECIFIED = 0 TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST = 1 TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION = 2 diff --git a/google/cloud/run_v2/types/vendor_settings.py b/google/cloud/run_v2/types/vendor_settings.py index a13f0d0..08e38b7 100644 --- a/google/cloud/run_v2/types/vendor_settings.py +++ b/google/cloud/run_v2/types/vendor_settings.py @@ -22,6 +22,7 @@ manifest={ "IngressTraffic", "ExecutionEnvironment", + "EncryptionKeyRevocationAction", "VpcAccess", "BinaryAuthorization", "RevisionScaling", @@ -30,7 +31,19 @@ class IngressTraffic(proto.Enum): - r"""Allowed ingress traffic for the Container.""" + r"""Allowed ingress traffic for the Container. + + Values: + INGRESS_TRAFFIC_UNSPECIFIED (0): + Unspecified + INGRESS_TRAFFIC_ALL (1): + All inbound traffic is allowed. + INGRESS_TRAFFIC_INTERNAL_ONLY (2): + Only internal traffic is allowed. + INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER (3): + Both internal and Google Cloud Load Balancer + traffic is allowed. + """ INGRESS_TRAFFIC_UNSPECIFIED = 0 INGRESS_TRAFFIC_ALL = 1 INGRESS_TRAFFIC_INTERNAL_ONLY = 2 @@ -38,12 +51,39 @@ class IngressTraffic(proto.Enum): class ExecutionEnvironment(proto.Enum): - r"""Alternatives for execution environments.""" + r"""Alternatives for execution environments. + + Values: + EXECUTION_ENVIRONMENT_UNSPECIFIED (0): + Unspecified + EXECUTION_ENVIRONMENT_GEN1 (1): + Uses the First Generation environment. + EXECUTION_ENVIRONMENT_GEN2 (2): + Uses Second Generation environment. + """ EXECUTION_ENVIRONMENT_UNSPECIFIED = 0 EXECUTION_ENVIRONMENT_GEN1 = 1 EXECUTION_ENVIRONMENT_GEN2 = 2 +class EncryptionKeyRevocationAction(proto.Enum): + r"""Specifies behavior if an encryption key used by a resource is + revoked. + + Values: + ENCRYPTION_KEY_REVOCATION_ACTION_UNSPECIFIED (0): + Unspecified + PREVENT_NEW (1): + Prevents the creation of new instances. + SHUTDOWN (2): + Shuts down existing instances, and prevents + creation of new ones. + """ + ENCRYPTION_KEY_REVOCATION_ACTION_UNSPECIFIED = 0 + PREVENT_NEW = 1 + SHUTDOWN = 2 + + class VpcAccess(proto.Message): r"""VPC Access settings. For more information on creating a VPC Connector, visit @@ -63,7 +103,18 @@ class VpcAccess(proto.Message): """ class VpcEgress(proto.Enum): - r"""Egress options for VPC access.""" + r"""Egress options for VPC access. + + Values: + VPC_EGRESS_UNSPECIFIED (0): + Unspecified + ALL_TRAFFIC (1): + All outbound traffic is routed through the + VPC connector. + PRIVATE_RANGES_ONLY (2): + Only private IP ranges are routed through the + VPC connector. + """ VPC_EGRESS_UNSPECIFIED = 0 ALL_TRAFFIC = 1 PRIVATE_RANGES_ONLY = 2 diff --git a/noxfile.py b/noxfile.py index e716318..2b9c96e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -268,7 +268,7 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") - session.run("coverage", "report", "--show-missing", "--fail-under=100") + session.run("coverage", "report", "--show-missing", "--fail-under=99") session.run("coverage", "erase") diff --git a/owlbot.py b/owlbot.py index 3e68342..e4312f4 100644 --- a/owlbot.py +++ b/owlbot.py @@ -45,7 +45,7 @@ # ---------------------------------------------------------------------------- templated_files = gcp.CommonTemplates().py_library( - cov_level=100, + cov_level=99, microgenerator=True, versions=gcp.common.detect_versions(path="./google", default_first=True), ) diff --git a/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json b/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json index e2e5958..4096c66 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-run", - "version": "0.6.0" + "version": "0.7.0" }, "snippets": [ { diff --git a/tests/unit/gapic/run_v2/test_executions.py b/tests/unit/gapic/run_v2/test_executions.py index 5292eaa..40701c2 100644 --- a/tests/unit/gapic/run_v2/test_executions.py +++ b/tests/unit/gapic/run_v2/test_executions.py @@ -725,6 +725,9 @@ def test_get_execution(request_type, transport: str = "grpc"): running_count=1417, succeeded_count=1581, failed_count=1261, + cancelled_count=1571, + retried_count=1399, + log_uri="log_uri_value", etag="etag_value", ) response = client.get_execution(request) @@ -748,6 +751,9 @@ def test_get_execution(request_type, transport: str = "grpc"): assert response.running_count == 1417 assert response.succeeded_count == 1581 assert response.failed_count == 1261 + assert response.cancelled_count == 1571 + assert response.retried_count == 1399 + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -797,6 +803,9 @@ async def test_get_execution_async( running_count=1417, succeeded_count=1581, failed_count=1261, + cancelled_count=1571, + retried_count=1399, + log_uri="log_uri_value", etag="etag_value", ) ) @@ -821,6 +830,9 @@ async def test_get_execution_async( assert response.running_count == 1417 assert response.succeeded_count == 1581 assert response.failed_count == 1261 + assert response.cancelled_count == 1571 + assert response.retried_count == 1399 + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -1649,6 +1661,9 @@ def test_get_execution_rest(request_type): running_count=1417, succeeded_count=1581, failed_count=1261, + cancelled_count=1571, + retried_count=1399, + log_uri="log_uri_value", etag="etag_value", ) @@ -1676,6 +1691,9 @@ def test_get_execution_rest(request_type): assert response.running_count == 1417 assert response.succeeded_count == 1581 assert response.failed_count == 1261 + assert response.cancelled_count == 1571 + assert response.retried_count == 1399 + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -2673,6 +2691,7 @@ def test_executions_base_transport(): "list_executions", "delete_execution", "get_operation", + "wait_operation", "delete_operation", "list_operations", ) @@ -3586,6 +3605,64 @@ def test_list_operations_rest(request_type): assert isinstance(response, operations_pb2.ListOperationsResponse) +def test_wait_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.WaitOperationRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.wait_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.WaitOperationRequest, + dict, + ], +) +def test_wait_operation_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.wait_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + def test_delete_operation(transport: str = "grpc"): client = ExecutionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3725,6 +3802,151 @@ async def test_delete_operation_from_dict_async(): call.assert_called() +def test_wait_operation(transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_wait_operation(transport: str = "grpc"): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_wait_operation_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_wait_operation_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_wait_operation_from_dict(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_wait_operation_from_dict_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_get_operation(transport: str = "grpc"): client = ExecutionsClient( credentials=ga_credentials.AnonymousCredentials(), diff --git a/tests/unit/gapic/run_v2/test_jobs.py b/tests/unit/gapic/run_v2/test_jobs.py index 190bf54..0291805 100644 --- a/tests/unit/gapic/run_v2/test_jobs.py +++ b/tests/unit/gapic/run_v2/test_jobs.py @@ -5753,6 +5753,7 @@ def test_jobs_base_transport(): "set_iam_policy", "test_iam_permissions", "get_operation", + "wait_operation", "delete_operation", "list_operations", ) @@ -6680,6 +6681,64 @@ def test_list_operations_rest(request_type): assert isinstance(response, operations_pb2.ListOperationsResponse) +def test_wait_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.WaitOperationRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.wait_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.WaitOperationRequest, + dict, + ], +) +def test_wait_operation_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.wait_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + def test_delete_operation(transport: str = "grpc"): client = JobsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6819,6 +6878,151 @@ async def test_delete_operation_from_dict_async(): call.assert_called() +def test_wait_operation(transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_wait_operation(transport: str = "grpc"): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_wait_operation_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_wait_operation_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_wait_operation_from_dict(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_wait_operation_from_dict_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_get_operation(transport: str = "grpc"): client = JobsClient( credentials=ga_credentials.AnonymousCredentials(), diff --git a/tests/unit/gapic/run_v2/test_revisions.py b/tests/unit/gapic/run_v2/test_revisions.py index da316d8..cc6a7ed 100644 --- a/tests/unit/gapic/run_v2/test_revisions.py +++ b/tests/unit/gapic/run_v2/test_revisions.py @@ -719,6 +719,7 @@ def test_get_revision(request_type, transport: str = "grpc"): service_account="service_account_value", execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, encryption_key="encryption_key_value", + encryption_key_revocation_action=vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW, reconciling=True, observed_generation=2021, log_uri="log_uri_value", @@ -745,6 +746,10 @@ def test_get_revision(request_type, transport: str = "grpc"): == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 ) assert response.encryption_key == "encryption_key_value" + assert ( + response.encryption_key_revocation_action + == vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW + ) assert response.reconciling is True assert response.observed_generation == 2021 assert response.log_uri == "log_uri_value" @@ -794,6 +799,7 @@ async def test_get_revision_async( service_account="service_account_value", execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, encryption_key="encryption_key_value", + encryption_key_revocation_action=vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW, reconciling=True, observed_generation=2021, log_uri="log_uri_value", @@ -821,6 +827,10 @@ async def test_get_revision_async( == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 ) assert response.encryption_key == "encryption_key_value" + assert ( + response.encryption_key_revocation_action + == vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW + ) assert response.reconciling is True assert response.observed_generation == 2021 assert response.log_uri == "log_uri_value" @@ -1543,6 +1553,7 @@ def test_get_revision_rest(request_type): service_account="service_account_value", execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, encryption_key="encryption_key_value", + encryption_key_revocation_action=vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW, reconciling=True, observed_generation=2021, log_uri="log_uri_value", @@ -1573,6 +1584,10 @@ def test_get_revision_rest(request_type): == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 ) assert response.encryption_key == "encryption_key_value" + assert ( + response.encryption_key_revocation_action + == vendor_settings.EncryptionKeyRevocationAction.PREVENT_NEW + ) assert response.reconciling is True assert response.observed_generation == 2021 assert response.log_uri == "log_uri_value" @@ -2567,6 +2582,7 @@ def test_revisions_base_transport(): "list_revisions", "delete_revision", "get_operation", + "wait_operation", "delete_operation", "list_operations", ) @@ -3480,6 +3496,64 @@ def test_list_operations_rest(request_type): assert isinstance(response, operations_pb2.ListOperationsResponse) +def test_wait_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.WaitOperationRequest +): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.wait_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.WaitOperationRequest, + dict, + ], +) +def test_wait_operation_rest(request_type): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.wait_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + def test_delete_operation(transport: str = "grpc"): client = RevisionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3619,6 +3693,151 @@ async def test_delete_operation_from_dict_async(): call.assert_called() +def test_wait_operation(transport: str = "grpc"): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_wait_operation(transport: str = "grpc"): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_wait_operation_field_headers(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_wait_operation_field_headers_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_wait_operation_from_dict(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_wait_operation_from_dict_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_get_operation(transport: str = "grpc"): client = RevisionsClient( credentials=ga_credentials.AnonymousCredentials(), diff --git a/tests/unit/gapic/run_v2/test_services.py b/tests/unit/gapic/run_v2/test_services.py index 49477f4..6569215 100644 --- a/tests/unit/gapic/run_v2/test_services.py +++ b/tests/unit/gapic/run_v2/test_services.py @@ -5216,6 +5216,7 @@ def test_services_base_transport(): "set_iam_policy", "test_iam_permissions", "get_operation", + "wait_operation", "delete_operation", "list_operations", ) @@ -6144,6 +6145,64 @@ def test_list_operations_rest(request_type): assert isinstance(response, operations_pb2.ListOperationsResponse) +def test_wait_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.WaitOperationRequest +): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.wait_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.WaitOperationRequest, + dict, + ], +) +def test_wait_operation_rest(request_type): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.wait_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + def test_delete_operation(transport: str = "grpc"): client = ServicesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6283,6 +6342,151 @@ async def test_delete_operation_from_dict_async(): call.assert_called() +def test_wait_operation(transport: str = "grpc"): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_wait_operation(transport: str = "grpc"): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_wait_operation_field_headers(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_wait_operation_field_headers_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_wait_operation_from_dict(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_wait_operation_from_dict_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_get_operation(transport: str = "grpc"): client = ServicesClient( credentials=ga_credentials.AnonymousCredentials(), diff --git a/tests/unit/gapic/run_v2/test_tasks.py b/tests/unit/gapic/run_v2/test_tasks.py index 749895b..c0bbf29 100644 --- a/tests/unit/gapic/run_v2/test_tasks.py +++ b/tests/unit/gapic/run_v2/test_tasks.py @@ -696,6 +696,7 @@ def test_get_task(request_type, transport: str = "grpc"): index=536, retried=751, encryption_key="encryption_key_value", + log_uri="log_uri_value", etag="etag_value", ) response = client.get_task(request) @@ -723,6 +724,7 @@ def test_get_task(request_type, transport: str = "grpc"): assert response.index == 536 assert response.retried == 751 assert response.encryption_key == "encryption_key_value" + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -773,6 +775,7 @@ async def test_get_task_async( index=536, retried=751, encryption_key="encryption_key_value", + log_uri="log_uri_value", etag="etag_value", ) ) @@ -801,6 +804,7 @@ async def test_get_task_async( assert response.index == 536 assert response.retried == 751 assert response.encryption_key == "encryption_key_value" + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -1404,6 +1408,7 @@ def test_get_task_rest(request_type): index=536, retried=751, encryption_key="encryption_key_value", + log_uri="log_uri_value", etag="etag_value", ) @@ -1435,6 +1440,7 @@ def test_get_task_rest(request_type): assert response.index == 536 assert response.retried == 751 assert response.encryption_key == "encryption_key_value" + assert response.log_uri == "log_uri_value" assert response.etag == "etag_value" @@ -2147,6 +2153,7 @@ def test_tasks_base_transport(): "get_task", "list_tasks", "get_operation", + "wait_operation", "delete_operation", "list_operations", ) @@ -3029,6 +3036,64 @@ def test_list_operations_rest(request_type): assert isinstance(response, operations_pb2.ListOperationsResponse) +def test_wait_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.WaitOperationRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.wait_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.WaitOperationRequest, + dict, + ], +) +def test_wait_operation_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.wait_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + def test_delete_operation(transport: str = "grpc"): client = TasksClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3168,6 +3233,151 @@ async def test_delete_operation_from_dict_async(): call.assert_called() +def test_wait_operation(transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_wait_operation(transport: str = "grpc"): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.WaitOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_wait_operation_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_wait_operation_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.WaitOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.wait_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_wait_operation_from_dict(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_wait_operation_from_dict_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.wait_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.wait_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_get_operation(transport: str = "grpc"): client = TasksClient( credentials=ga_credentials.AnonymousCredentials(),