From a242adc8864724acb2d12136bb09d68cb7fc729c Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Sat, 24 Jul 2021 10:24:11 +0000 Subject: [PATCH] feat: Change metadata field for the AnalyzeIamPolicyLongrunning (#245) *the metadata field change for AnalyzeIamPolicyLongrunning is BACKWARD INCOMPATIBLE. Adding this change expand our ability to return richer metadata information for the longrunning operation. Due to the small usage of this API, we've contacted all the customers to make sure they are not using the metadata field and hence won't be broken by this change. Committer: @aaronlichen-hp PiperOrigin-RevId: 386530026 Source-Link: https://github.com/googleapis/googleapis/commit/746461e4242e8d8bf2e2e78994784dba55c5ec31 Source-Link: https://github.com/googleapis/googleapis-gen/commit/c2c174583aa7c18ab206bf8c54e6b1143a0e6d5c feat: Add AnalyzeMove API feat: Add read_mask field for SearchAllResourcesRequest feat: Add VersionedResource field for ResourceSearchResult feat: Add AttachedResource field for ResourceSearchResult --- google/cloud/asset/__init__.py | 18 ++ google/cloud/asset_v1/__init__.py | 16 ++ google/cloud/asset_v1/gapic_metadata.json | 10 ++ .../services/asset_service/async_client.py | 65 ++++++- .../asset_v1/services/asset_service/client.py | 66 ++++++- .../services/asset_service/transports/base.py | 15 ++ .../services/asset_service/transports/grpc.py | 38 +++- .../asset_service/transports/grpc_asyncio.py | 38 +++- google/cloud/asset_v1/types/__init__.py | 16 ++ google/cloud/asset_v1/types/asset_service.py | 168 +++++++++++++++++- google/cloud/asset_v1/types/assets.py | 85 +++++++++ scripts/fixup_asset_v1_keywords.py | 3 +- .../unit/gapic/asset_v1/test_asset_service.py | 131 ++++++++++++++ 13 files changed, 647 insertions(+), 22 deletions(-) diff --git a/google/cloud/asset/__init__.py b/google/cloud/asset/__init__.py index ede0c218..b4309178 100644 --- a/google/cloud/asset/__init__.py +++ b/google/cloud/asset/__init__.py @@ -19,12 +19,17 @@ AssetServiceAsyncClient, ) +from google.cloud.asset_v1.types.asset_service import ( + AnalyzeIamPolicyLongrunningMetadata, +) from google.cloud.asset_v1.types.asset_service import AnalyzeIamPolicyLongrunningRequest from google.cloud.asset_v1.types.asset_service import ( AnalyzeIamPolicyLongrunningResponse, ) from google.cloud.asset_v1.types.asset_service import AnalyzeIamPolicyRequest from google.cloud.asset_v1.types.asset_service import AnalyzeIamPolicyResponse +from google.cloud.asset_v1.types.asset_service import AnalyzeMoveRequest +from google.cloud.asset_v1.types.asset_service import AnalyzeMoveResponse from google.cloud.asset_v1.types.asset_service import BatchGetAssetsHistoryRequest from google.cloud.asset_v1.types.asset_service import BatchGetAssetsHistoryResponse from google.cloud.asset_v1.types.asset_service import BigQueryDestination @@ -43,6 +48,9 @@ from google.cloud.asset_v1.types.asset_service import ListAssetsResponse from google.cloud.asset_v1.types.asset_service import ListFeedsRequest from google.cloud.asset_v1.types.asset_service import ListFeedsResponse +from google.cloud.asset_v1.types.asset_service import MoveAnalysis +from google.cloud.asset_v1.types.asset_service import MoveAnalysisResult +from google.cloud.asset_v1.types.asset_service import MoveImpact from google.cloud.asset_v1.types.asset_service import OutputConfig from google.cloud.asset_v1.types.asset_service import OutputResult from google.cloud.asset_v1.types.asset_service import PartitionSpec @@ -54,6 +62,7 @@ from google.cloud.asset_v1.types.asset_service import UpdateFeedRequest from google.cloud.asset_v1.types.asset_service import ContentType from google.cloud.asset_v1.types.assets import Asset +from google.cloud.asset_v1.types.assets import AttachedResource from google.cloud.asset_v1.types.assets import ConditionEvaluation from google.cloud.asset_v1.types.assets import IamPolicyAnalysisResult from google.cloud.asset_v1.types.assets import IamPolicyAnalysisState @@ -62,14 +71,18 @@ from google.cloud.asset_v1.types.assets import ResourceSearchResult from google.cloud.asset_v1.types.assets import TemporalAsset from google.cloud.asset_v1.types.assets import TimeWindow +from google.cloud.asset_v1.types.assets import VersionedResource __all__ = ( "AssetServiceClient", "AssetServiceAsyncClient", + "AnalyzeIamPolicyLongrunningMetadata", "AnalyzeIamPolicyLongrunningRequest", "AnalyzeIamPolicyLongrunningResponse", "AnalyzeIamPolicyRequest", "AnalyzeIamPolicyResponse", + "AnalyzeMoveRequest", + "AnalyzeMoveResponse", "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", "BigQueryDestination", @@ -88,6 +101,9 @@ "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", + "MoveAnalysis", + "MoveAnalysisResult", + "MoveImpact", "OutputConfig", "OutputResult", "PartitionSpec", @@ -99,6 +115,7 @@ "UpdateFeedRequest", "ContentType", "Asset", + "AttachedResource", "ConditionEvaluation", "IamPolicyAnalysisResult", "IamPolicyAnalysisState", @@ -107,4 +124,5 @@ "ResourceSearchResult", "TemporalAsset", "TimeWindow", + "VersionedResource", ) diff --git a/google/cloud/asset_v1/__init__.py b/google/cloud/asset_v1/__init__.py index 92bbf9e9..ada8ad1c 100644 --- a/google/cloud/asset_v1/__init__.py +++ b/google/cloud/asset_v1/__init__.py @@ -17,10 +17,13 @@ from .services.asset_service import AssetServiceClient from .services.asset_service import AssetServiceAsyncClient +from .types.asset_service import AnalyzeIamPolicyLongrunningMetadata from .types.asset_service import AnalyzeIamPolicyLongrunningRequest from .types.asset_service import AnalyzeIamPolicyLongrunningResponse from .types.asset_service import AnalyzeIamPolicyRequest from .types.asset_service import AnalyzeIamPolicyResponse +from .types.asset_service import AnalyzeMoveRequest +from .types.asset_service import AnalyzeMoveResponse from .types.asset_service import BatchGetAssetsHistoryRequest from .types.asset_service import BatchGetAssetsHistoryResponse from .types.asset_service import BigQueryDestination @@ -39,6 +42,9 @@ from .types.asset_service import ListAssetsResponse from .types.asset_service import ListFeedsRequest from .types.asset_service import ListFeedsResponse +from .types.asset_service import MoveAnalysis +from .types.asset_service import MoveAnalysisResult +from .types.asset_service import MoveImpact from .types.asset_service import OutputConfig from .types.asset_service import OutputResult from .types.asset_service import PartitionSpec @@ -50,6 +56,7 @@ from .types.asset_service import UpdateFeedRequest from .types.asset_service import ContentType from .types.assets import Asset +from .types.assets import AttachedResource from .types.assets import ConditionEvaluation from .types.assets import IamPolicyAnalysisResult from .types.assets import IamPolicyAnalysisState @@ -58,15 +65,20 @@ from .types.assets import ResourceSearchResult from .types.assets import TemporalAsset from .types.assets import TimeWindow +from .types.assets import VersionedResource __all__ = ( "AssetServiceAsyncClient", + "AnalyzeIamPolicyLongrunningMetadata", "AnalyzeIamPolicyLongrunningRequest", "AnalyzeIamPolicyLongrunningResponse", "AnalyzeIamPolicyRequest", "AnalyzeIamPolicyResponse", + "AnalyzeMoveRequest", + "AnalyzeMoveResponse", "Asset", "AssetServiceClient", + "AttachedResource", "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", "BigQueryDestination", @@ -90,6 +102,9 @@ "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", + "MoveAnalysis", + "MoveAnalysisResult", + "MoveImpact", "OutputConfig", "OutputResult", "PartitionSpec", @@ -103,4 +118,5 @@ "TemporalAsset", "TimeWindow", "UpdateFeedRequest", + "VersionedResource", ) diff --git a/google/cloud/asset_v1/gapic_metadata.json b/google/cloud/asset_v1/gapic_metadata.json index eebf25a1..dea0335c 100644 --- a/google/cloud/asset_v1/gapic_metadata.json +++ b/google/cloud/asset_v1/gapic_metadata.json @@ -20,6 +20,11 @@ "analyze_iam_policy_longrunning" ] }, + "AnalyzeMove": { + "methods": [ + "analyze_move" + ] + }, "BatchGetAssetsHistory": { "methods": [ "batch_get_assets_history" @@ -85,6 +90,11 @@ "analyze_iam_policy_longrunning" ] }, + "AnalyzeMove": { + "methods": [ + "analyze_move" + ] + }, "BatchGetAssetsHistory": { "methods": [ "batch_get_assets_history" diff --git a/google/cloud/asset_v1/services/asset_service/async_client.py b/google/cloud/asset_v1/services/asset_service/async_client.py index b56b0f30..5546a37b 100644 --- a/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1/services/asset_service/async_client.py @@ -864,8 +864,8 @@ async def search_all_resources( the word "key". - ``state:ACTIVE`` to find Cloud resources whose state contains "ACTIVE" as a word. - - ``NOT state:ACTIVE`` to find {{gcp_name}} resources - whose state doesn't contain "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find Cloud resources whose + state doesn't contain "ACTIVE" as a word. - ``createTime<1609459200`` to find Cloud resources that were created before "2021-01-01 00:00:00 UTC". 1609459200 is the epoch timestamp of "2021-01-01 @@ -1221,8 +1221,8 @@ async def analyze_iam_policy_longrunning( [google.longrunning.Operation][google.longrunning.Operation], which allows you to track the operation status. We recommend intervals of at least 2 seconds with exponential backoff retry - to poll the operation result. The metadata contains the request - to help callers to map responses to requests. + to poll the operation result. The metadata contains the metadata + for the long-running operation. Args: request (:class:`google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningRequest`): @@ -1271,12 +1271,67 @@ async def analyze_iam_policy_longrunning( response, self._client._transport.operations_client, asset_service.AnalyzeIamPolicyLongrunningResponse, - metadata_type=asset_service.AnalyzeIamPolicyLongrunningRequest, + metadata_type=asset_service.AnalyzeIamPolicyLongrunningMetadata, ) # Done; return the response. return response + async def analyze_move( + self, + request: asset_service.AnalyzeMoveRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeMoveResponse: + r"""Analyze moving a resource to a specified destination + without kicking off the actual move. The analysis is + best effort depending on the user's permissions of + viewing different hierarchical policies and + configurations. The policies and configuration are + subject to change before the actual resource migration + takes place. + + Args: + request (:class:`google.cloud.asset_v1.types.AnalyzeMoveRequest`): + The request object. The request message for performing + resource move analysis. + 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: + google.cloud.asset_v1.types.AnalyzeMoveResponse: + The response message for resource + move analysis. + + """ + # Create or coerce a protobuf request object. + request = asset_service.AnalyzeMoveRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.analyze_move, + 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((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/asset_v1/services/asset_service/client.py b/google/cloud/asset_v1/services/asset_service/client.py index 38c7ce3d..6459c846 100644 --- a/google/cloud/asset_v1/services/asset_service/client.py +++ b/google/cloud/asset_v1/services/asset_service/client.py @@ -1005,8 +1005,8 @@ def search_all_resources( the word "key". - ``state:ACTIVE`` to find Cloud resources whose state contains "ACTIVE" as a word. - - ``NOT state:ACTIVE`` to find {{gcp_name}} resources - whose state doesn't contain "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find Cloud resources whose + state doesn't contain "ACTIVE" as a word. - ``createTime<1609459200`` to find Cloud resources that were created before "2021-01-01 00:00:00 UTC". 1609459200 is the epoch timestamp of "2021-01-01 @@ -1336,8 +1336,8 @@ def analyze_iam_policy_longrunning( [google.longrunning.Operation][google.longrunning.Operation], which allows you to track the operation status. We recommend intervals of at least 2 seconds with exponential backoff retry - to poll the operation result. The metadata contains the request - to help callers to map responses to requests. + to poll the operation result. The metadata contains the metadata + for the long-running operation. Args: request (google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningRequest): @@ -1389,12 +1389,68 @@ def analyze_iam_policy_longrunning( response, self._transport.operations_client, asset_service.AnalyzeIamPolicyLongrunningResponse, - metadata_type=asset_service.AnalyzeIamPolicyLongrunningRequest, + metadata_type=asset_service.AnalyzeIamPolicyLongrunningMetadata, ) # Done; return the response. return response + def analyze_move( + self, + request: asset_service.AnalyzeMoveRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeMoveResponse: + r"""Analyze moving a resource to a specified destination + without kicking off the actual move. The analysis is + best effort depending on the user's permissions of + viewing different hierarchical policies and + configurations. The policies and configuration are + subject to change before the actual resource migration + takes place. + + Args: + request (google.cloud.asset_v1.types.AnalyzeMoveRequest): + The request object. The request message for performing + resource move analysis. + 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: + google.cloud.asset_v1.types.AnalyzeMoveResponse: + The response message for resource + move analysis. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a asset_service.AnalyzeMoveRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, asset_service.AnalyzeMoveRequest): + request = asset_service.AnalyzeMoveRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.analyze_move] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/asset_v1/services/asset_service/transports/base.py b/google/cloud/asset_v1/services/asset_service/transports/base.py index e15d7266..263026e0 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1/services/asset_service/transports/base.py @@ -286,6 +286,9 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.analyze_move: gapic_v1.method.wrap_method( + self.analyze_move, default_timeout=None, client_info=client_info, + ), } @property @@ -418,5 +421,17 @@ def analyze_iam_policy_longrunning( ]: raise NotImplementedError() + @property + def analyze_move( + self, + ) -> Callable[ + [asset_service.AnalyzeMoveRequest], + Union[ + asset_service.AnalyzeMoveResponse, + Awaitable[asset_service.AnalyzeMoveResponse], + ], + ]: + raise NotImplementedError() + __all__ = ("AssetServiceTransport",) diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1/services/asset_service/transports/grpc.py index 177e4a3a..57211806 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc.py @@ -585,8 +585,8 @@ def analyze_iam_policy_longrunning( [google.longrunning.Operation][google.longrunning.Operation], which allows you to track the operation status. We recommend intervals of at least 2 seconds with exponential backoff retry - to poll the operation result. The metadata contains the request - to help callers to map responses to requests. + to poll the operation result. The metadata contains the metadata + for the long-running operation. Returns: Callable[[~.AnalyzeIamPolicyLongrunningRequest], @@ -608,5 +608,39 @@ def analyze_iam_policy_longrunning( ) return self._stubs["analyze_iam_policy_longrunning"] + @property + def analyze_move( + self, + ) -> Callable[ + [asset_service.AnalyzeMoveRequest], asset_service.AnalyzeMoveResponse + ]: + r"""Return a callable for the analyze move method over gRPC. + + Analyze moving a resource to a specified destination + without kicking off the actual move. The analysis is + best effort depending on the user's permissions of + viewing different hierarchical policies and + configurations. The policies and configuration are + subject to change before the actual resource migration + takes place. + + Returns: + Callable[[~.AnalyzeMoveRequest], + ~.AnalyzeMoveResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # 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 "analyze_move" not in self._stubs: + self._stubs["analyze_move"] = self.grpc_channel.unary_unary( + "/google.cloud.asset.v1.AssetService/AnalyzeMove", + request_serializer=asset_service.AnalyzeMoveRequest.serialize, + response_deserializer=asset_service.AnalyzeMoveResponse.deserialize, + ) + return self._stubs["analyze_move"] + __all__ = ("AssetServiceGrpcTransport",) diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py index 7df1ccb4..74e79b1e 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py @@ -600,8 +600,8 @@ def analyze_iam_policy_longrunning( [google.longrunning.Operation][google.longrunning.Operation], which allows you to track the operation status. We recommend intervals of at least 2 seconds with exponential backoff retry - to poll the operation result. The metadata contains the request - to help callers to map responses to requests. + to poll the operation result. The metadata contains the metadata + for the long-running operation. Returns: Callable[[~.AnalyzeIamPolicyLongrunningRequest], @@ -623,5 +623,39 @@ def analyze_iam_policy_longrunning( ) return self._stubs["analyze_iam_policy_longrunning"] + @property + def analyze_move( + self, + ) -> Callable[ + [asset_service.AnalyzeMoveRequest], Awaitable[asset_service.AnalyzeMoveResponse] + ]: + r"""Return a callable for the analyze move method over gRPC. + + Analyze moving a resource to a specified destination + without kicking off the actual move. The analysis is + best effort depending on the user's permissions of + viewing different hierarchical policies and + configurations. The policies and configuration are + subject to change before the actual resource migration + takes place. + + Returns: + Callable[[~.AnalyzeMoveRequest], + Awaitable[~.AnalyzeMoveResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # 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 "analyze_move" not in self._stubs: + self._stubs["analyze_move"] = self.grpc_channel.unary_unary( + "/google.cloud.asset.v1.AssetService/AnalyzeMove", + request_serializer=asset_service.AnalyzeMoveRequest.serialize, + response_deserializer=asset_service.AnalyzeMoveResponse.deserialize, + ) + return self._stubs["analyze_move"] + __all__ = ("AssetServiceGrpcAsyncIOTransport",) diff --git a/google/cloud/asset_v1/types/__init__.py b/google/cloud/asset_v1/types/__init__.py index 600d11c3..4a220650 100644 --- a/google/cloud/asset_v1/types/__init__.py +++ b/google/cloud/asset_v1/types/__init__.py @@ -14,10 +14,13 @@ # limitations under the License. # from .asset_service import ( + AnalyzeIamPolicyLongrunningMetadata, AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, AnalyzeIamPolicyRequest, AnalyzeIamPolicyResponse, + AnalyzeMoveRequest, + AnalyzeMoveResponse, BatchGetAssetsHistoryRequest, BatchGetAssetsHistoryResponse, BigQueryDestination, @@ -36,6 +39,9 @@ ListAssetsResponse, ListFeedsRequest, ListFeedsResponse, + MoveAnalysis, + MoveAnalysisResult, + MoveImpact, OutputConfig, OutputResult, PartitionSpec, @@ -49,6 +55,7 @@ ) from .assets import ( Asset, + AttachedResource, ConditionEvaluation, IamPolicyAnalysisResult, IamPolicyAnalysisState, @@ -57,13 +64,17 @@ ResourceSearchResult, TemporalAsset, TimeWindow, + VersionedResource, ) __all__ = ( + "AnalyzeIamPolicyLongrunningMetadata", "AnalyzeIamPolicyLongrunningRequest", "AnalyzeIamPolicyLongrunningResponse", "AnalyzeIamPolicyRequest", "AnalyzeIamPolicyResponse", + "AnalyzeMoveRequest", + "AnalyzeMoveResponse", "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", "BigQueryDestination", @@ -82,6 +93,9 @@ "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", + "MoveAnalysis", + "MoveAnalysisResult", + "MoveImpact", "OutputConfig", "OutputResult", "PartitionSpec", @@ -93,6 +107,7 @@ "UpdateFeedRequest", "ContentType", "Asset", + "AttachedResource", "ConditionEvaluation", "IamPolicyAnalysisResult", "IamPolicyAnalysisState", @@ -101,4 +116,5 @@ "ResourceSearchResult", "TemporalAsset", "TimeWindow", + "VersionedResource", ) diff --git a/google/cloud/asset_v1/types/asset_service.py b/google/cloud/asset_v1/types/asset_service.py index bb0dd094..6794d437 100644 --- a/google/cloud/asset_v1/types/asset_service.py +++ b/google/cloud/asset_v1/types/asset_service.py @@ -19,6 +19,7 @@ from google.protobuf import duration_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.rpc import status_pb2 # type: ignore from google.type import expr_pb2 # type: ignore @@ -26,6 +27,7 @@ package="google.cloud.asset.v1", manifest={ "ContentType", + "AnalyzeIamPolicyLongrunningMetadata", "ExportAssetsRequest", "ExportAssetsResponse", "ListAssetsRequest", @@ -57,6 +59,11 @@ "IamPolicyAnalysisOutputConfig", "AnalyzeIamPolicyLongrunningRequest", "AnalyzeIamPolicyLongrunningResponse", + "AnalyzeMoveRequest", + "AnalyzeMoveResponse", + "MoveAnalysis", + "MoveAnalysisResult", + "MoveImpact", }, ) @@ -71,6 +78,18 @@ class ContentType(proto.Enum): OS_INVENTORY = 6 +class AnalyzeIamPolicyLongrunningMetadata(proto.Message): + r"""Represents the metadata of the longrunning operation for the + AnalyzeIamPolicyLongrunning rpc. + + Attributes: + create_time (google.protobuf.timestamp_pb2.Timestamp): + The time the operation was created. + """ + + create_time = proto.Field(proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,) + + class ExportAssetsRequest(proto.Message): r"""Export asset request. Attributes: @@ -654,7 +673,7 @@ class Feed(proto.Message): optional. See our `user - guide `__ + guide `__ for detailed instructions. """ @@ -713,8 +732,8 @@ class SearchAllResourcesRequest(proto.Message): word "key". - ``state:ACTIVE`` to find Cloud resources whose state contains "ACTIVE" as a word. - - ``NOT state:ACTIVE`` to find {{gcp_name}} resources whose - state doesn't contain "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find Cloud resources whose state + doesn't contain "ACTIVE" as a word. - ``createTime<1609459200`` to find Cloud resources that were created before "2021-01-01 00:00:00 UTC". 1609459200 is the epoch timestamp of "2021-01-01 00:00:00 UTC" in @@ -781,10 +800,42 @@ class SearchAllResourcesRequest(proto.Message): - updateTime - state - parentFullResourceName - - parentAssetType All the other fields such as repeated - fields (e.g., ``networkTags``), map fields (e.g., - ``labels``) and struct fields (e.g., - ``additionalAttributes``) are not supported. + - parentAssetType + + All the other fields such as repeated fields (e.g., + ``networkTags``), map fields (e.g., ``labels``) and struct + fields (e.g., ``additionalAttributes``) are not supported. + read_mask (google.protobuf.field_mask_pb2.FieldMask): + Optional. A comma-separated list of fields specifying which + fields to be returned in ResourceSearchResult. Only '*' or + combination of top level fields can be specified. Field + names of both snake_case and camelCase are supported. + Examples: ``"*"``, ``"name,location"``, + ``"name,versionedResources"``. + + The read_mask paths must be valid field paths listed but not + limited to (both snake_case and camelCase are supported): + + - name + - assetType + - project + - displayName + - description + - location + - labels + - networkTags + - kmsKey + - createTime + - updateTime + - state + - additionalAttributes + - versionedResources + + If read_mask is not specified, all fields except + versionedResources will be returned. If only '*' is + specified, all fields including versionedResources will be + returned. Any invalid field path will trigger + INVALID_ARGUMENT error. """ scope = proto.Field(proto.STRING, number=1,) @@ -793,6 +844,7 @@ class SearchAllResourcesRequest(proto.Message): page_size = proto.Field(proto.INT32, number=4,) page_token = proto.Field(proto.STRING, number=5,) order_by = proto.Field(proto.STRING, number=6,) + read_mask = proto.Field(proto.MESSAGE, number=8, message=field_mask_pb2.FieldMask,) class SearchAllResourcesResponse(proto.Message): @@ -1387,4 +1439,106 @@ class AnalyzeIamPolicyLongrunningResponse(proto.Message): """ +class AnalyzeMoveRequest(proto.Message): + r"""The request message for performing resource move analysis. + Attributes: + resource (str): + Required. Name of the resource to perform the + analysis against. Only GCP Project are supported + as of today. Hence, this can only be Project ID + (such as "projects/my-project-id") or a Project + Number (such as "projects/12345"). + destination_parent (str): + Required. Name of the GCP Folder or + Organization to reparent the target resource. + The analysis will be performed against + hypothetically moving the resource to this + specified desitination parent. This can only be + a Folder number (such as "folders/123") or an + Organization number (such as + "organizations/123"). + view (google.cloud.asset_v1.types.AnalyzeMoveRequest.AnalysisView): + Analysis view indicating what information + should be included in the analysis response. If + unspecified, the default view is FULL. + """ + + class AnalysisView(proto.Enum): + r"""View enum for supporting partial analysis responses.""" + ANALYSIS_VIEW_UNSPECIFIED = 0 + FULL = 1 + BASIC = 2 + + resource = proto.Field(proto.STRING, number=1,) + destination_parent = proto.Field(proto.STRING, number=2,) + view = proto.Field(proto.ENUM, number=3, enum=AnalysisView,) + + +class AnalyzeMoveResponse(proto.Message): + r"""The response message for resource move analysis. + Attributes: + move_analysis (Sequence[google.cloud.asset_v1.types.MoveAnalysis]): + The list of analyses returned from performing + the intended resource move analysis. The + analysis is grouped by different Cloud services. + """ + + move_analysis = proto.RepeatedField( + proto.MESSAGE, number=1, message="MoveAnalysis", + ) + + +class MoveAnalysis(proto.Message): + r"""A message to group the analysis information. + Attributes: + display_name (str): + The user friendly display name of the + analysis. E.g. IAM, Organization Policy etc. + analysis (google.cloud.asset_v1.types.MoveAnalysisResult): + Analysis result of moving the target + resource. + error (google.rpc.status_pb2.Status): + Description of error encountered when + performing the analysis. + """ + + display_name = proto.Field(proto.STRING, number=1,) + analysis = proto.Field( + proto.MESSAGE, number=2, oneof="result", message="MoveAnalysisResult", + ) + error = proto.Field( + proto.MESSAGE, number=3, oneof="result", message=status_pb2.Status, + ) + + +class MoveAnalysisResult(proto.Message): + r"""An analysis result including blockers and warnings. + Attributes: + blockers (Sequence[google.cloud.asset_v1.types.MoveImpact]): + Blocking information that would prevent the + target resource from moving to the specified + destination at runtime. + warnings (Sequence[google.cloud.asset_v1.types.MoveImpact]): + Warning information indicating that moving + the target resource to the specified destination + might be unsafe. This can include important + policy information and configuration changes, + but will not block moves at runtime. + """ + + blockers = proto.RepeatedField(proto.MESSAGE, number=1, message="MoveImpact",) + warnings = proto.RepeatedField(proto.MESSAGE, number=2, message="MoveImpact",) + + +class MoveImpact(proto.Message): + r"""A message to group impacts of moving the target resource. + Attributes: + detail (str): + User friendly impact detail in a free form + message. + """ + + detail = proto.Field(proto.STRING, number=1,) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/asset_v1/types/assets.py b/google/cloud/asset_v1/types/assets.py index 5778741c..a55efe1e 100644 --- a/google/cloud/asset_v1/types/assets.py +++ b/google/cloud/asset_v1/types/assets.py @@ -34,6 +34,8 @@ "Asset", "Resource", "ResourceSearchResult", + "VersionedResource", + "AttachedResource", "IamPolicySearchResult", "IamPolicyAnalysisState", "ConditionEvaluation", @@ -464,6 +466,25 @@ class ResourceSearchResult(proto.Message): - use a field query. Example: ``parentFullResourceName:"project-name"`` - use a free text query. Example: ``project-name`` + versioned_resources (Sequence[google.cloud.asset_v1.types.VersionedResource]): + Versioned resource representations of this resource. This is + repeated because there could be multiple versions of + resource representations during version migration. + + This ``versioned_resources`` field is not searchable. Some + attributes of the resource representations are exposed in + ``additional_attributes`` field, so as to allow users to + search on them. + attached_resources (Sequence[google.cloud.asset_v1.types.AttachedResource]): + Attached resources of this resource. For example, an + OSConfig Inventory is an attached resource of a Compute + Instance. This field is repeated because a resource could + have multiple attached resources. + + This ``attached_resources`` field is not searchable. Some + attributes of the attached resources are exposed in + ``additional_attributes`` field, so as to allow users to + search on them. parent_asset_type (str): The type of this resource's immediate parent, if there is one. @@ -498,9 +519,73 @@ class ResourceSearchResult(proto.Message): proto.MESSAGE, number=9, message=struct_pb2.Struct, ) parent_full_resource_name = proto.Field(proto.STRING, number=19,) + versioned_resources = proto.RepeatedField( + proto.MESSAGE, number=16, message="VersionedResource", + ) + attached_resources = proto.RepeatedField( + proto.MESSAGE, number=20, message="AttachedResource", + ) parent_asset_type = proto.Field(proto.STRING, number=103,) +class VersionedResource(proto.Message): + r"""Resource representation as defined by the corresponding + service providing the resource for a given API version. + + Attributes: + version (str): + API version of the resource. + + Example: If the resource is an instance provided by Compute + Engine v1 API as defined in + ``https://cloud.google.com/compute/docs/reference/rest/v1/instances``, + version will be "v1". + resource (google.protobuf.struct_pb2.Struct): + JSON representation of the resource as defined by the + corresponding service providing this resource. + + Example: If the resource is an instance provided by Compute + Engine, this field will contain the JSON representation of + the instance as defined by Compute Engine: + ``https://cloud.google.com/compute/docs/reference/rest/v1/instances``. + + You can find the resource definition for each supported + resource type in this table: + ``https://cloud.google.com/asset-inventory/docs/supported-asset-types#searchable_asset_types`` + """ + + version = proto.Field(proto.STRING, number=1,) + resource = proto.Field(proto.MESSAGE, number=2, message=struct_pb2.Struct,) + + +class AttachedResource(proto.Message): + r"""Attached resource representation, which is defined by the + corresponding service provider. It represents an attached + resource's payload. + + Attributes: + asset_type (str): + The type of this attached resource. + + Example: ``osconfig.googleapis.com/Inventory`` + + You can find the supported attached asset types of each + resource in this table: + ``https://cloud.google.com/asset-inventory/docs/supported-asset-types#searchable_asset_types`` + versioned_resources (Sequence[google.cloud.asset_v1.types.VersionedResource]): + Versioned resource representations of this + attached resource. This is repeated because + there could be multiple versions of the attached + resource representations during version + migration. + """ + + asset_type = proto.Field(proto.STRING, number=1,) + versioned_resources = proto.RepeatedField( + proto.MESSAGE, number=3, message="VersionedResource", + ) + + class IamPolicySearchResult(proto.Message): r"""A result of IAM Policy search, containing information of an IAM policy. diff --git a/scripts/fixup_asset_v1_keywords.py b/scripts/fixup_asset_v1_keywords.py index 4a9e79e9..5d5abef3 100644 --- a/scripts/fixup_asset_v1_keywords.py +++ b/scripts/fixup_asset_v1_keywords.py @@ -41,6 +41,7 @@ class assetCallTransformer(cst.CSTTransformer): METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { 'analyze_iam_policy': ('analysis_query', 'execution_timeout', ), 'analyze_iam_policy_longrunning': ('analysis_query', 'output_config', ), + 'analyze_move': ('resource', 'destination_parent', 'view', ), 'batch_get_assets_history': ('parent', 'asset_names', 'content_type', 'read_time_window', ), 'create_feed': ('parent', 'feed_id', 'feed', ), 'delete_feed': ('name', ), @@ -49,7 +50,7 @@ class assetCallTransformer(cst.CSTTransformer): 'list_assets': ('parent', 'read_time', 'asset_types', 'content_type', 'page_size', 'page_token', ), 'list_feeds': ('parent', ), 'search_all_iam_policies': ('scope', 'query', 'page_size', 'page_token', 'asset_types', 'order_by', ), - 'search_all_resources': ('scope', 'query', 'asset_types', 'page_size', 'page_token', 'order_by', ), + 'search_all_resources': ('scope', 'query', 'asset_types', 'page_size', 'page_token', 'order_by', 'read_mask', ), 'update_feed': ('feed', 'update_mask', ), } diff --git a/tests/unit/gapic/asset_v1/test_asset_service.py b/tests/unit/gapic/asset_v1/test_asset_service.py index d79cf14f..17926e1e 100644 --- a/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1/test_asset_service.py @@ -3149,6 +3149,136 @@ async def test_analyze_iam_policy_longrunning_field_headers_async(): ) in kw["metadata"] +def test_analyze_move( + transport: str = "grpc", request_type=asset_service.AnalyzeMoveRequest +): + client = AssetServiceClient( + 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 = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.analyze_move), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.AnalyzeMoveResponse() + response = client.analyze_move(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.AnalyzeMoveRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.AnalyzeMoveResponse) + + +def test_analyze_move_from_dict(): + test_analyze_move(request_type=dict) + + +def test_analyze_move_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.analyze_move), "__call__") as call: + client.analyze_move() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.AnalyzeMoveRequest() + + +@pytest.mark.asyncio +async def test_analyze_move_async( + transport: str = "grpc_asyncio", request_type=asset_service.AnalyzeMoveRequest +): + client = AssetServiceAsyncClient( + 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 = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.analyze_move), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + asset_service.AnalyzeMoveResponse() + ) + response = await client.analyze_move(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.AnalyzeMoveRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.AnalyzeMoveResponse) + + +@pytest.mark.asyncio +async def test_analyze_move_async_from_dict(): + await test_analyze_move_async(request_type=dict) + + +def test_analyze_move_field_headers(): + client = AssetServiceClient(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 = asset_service.AnalyzeMoveRequest() + + request.resource = "resource/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.analyze_move), "__call__") as call: + call.return_value = asset_service.AnalyzeMoveResponse() + client.analyze_move(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", "resource=resource/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_analyze_move_field_headers_async(): + client = AssetServiceAsyncClient(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 = asset_service.AnalyzeMoveRequest() + + request.resource = "resource/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.analyze_move), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + asset_service.AnalyzeMoveResponse() + ) + await client.analyze_move(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, 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", "resource=resource/value",) in kw["metadata"] + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AssetServiceGrpcTransport( @@ -3258,6 +3388,7 @@ def test_asset_service_base_transport(): "search_all_iam_policies", "analyze_iam_policy", "analyze_iam_policy_longrunning", + "analyze_move", ) for method in methods: with pytest.raises(NotImplementedError):