diff --git a/google/cloud/asset/__init__.py b/google/cloud/asset/__init__.py index 58379fd4..ede0c218 100644 --- a/google/cloud/asset/__init__.py +++ b/google/cloud/asset/__init__.py @@ -39,6 +39,8 @@ from google.cloud.asset_v1.types.asset_service import GetFeedRequest from google.cloud.asset_v1.types.asset_service import IamPolicyAnalysisOutputConfig from google.cloud.asset_v1.types.asset_service import IamPolicyAnalysisQuery +from google.cloud.asset_v1.types.asset_service import ListAssetsRequest +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 OutputConfig @@ -52,6 +54,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 ConditionEvaluation from google.cloud.asset_v1.types.assets import IamPolicyAnalysisResult from google.cloud.asset_v1.types.assets import IamPolicyAnalysisState from google.cloud.asset_v1.types.assets import IamPolicySearchResult @@ -81,6 +84,8 @@ "GetFeedRequest", "IamPolicyAnalysisOutputConfig", "IamPolicyAnalysisQuery", + "ListAssetsRequest", + "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", "OutputConfig", @@ -94,6 +99,7 @@ "UpdateFeedRequest", "ContentType", "Asset", + "ConditionEvaluation", "IamPolicyAnalysisResult", "IamPolicyAnalysisState", "IamPolicySearchResult", diff --git a/google/cloud/asset_v1/__init__.py b/google/cloud/asset_v1/__init__.py index 6c24e39c..92bbf9e9 100644 --- a/google/cloud/asset_v1/__init__.py +++ b/google/cloud/asset_v1/__init__.py @@ -35,6 +35,8 @@ from .types.asset_service import GetFeedRequest from .types.asset_service import IamPolicyAnalysisOutputConfig from .types.asset_service import IamPolicyAnalysisQuery +from .types.asset_service import ListAssetsRequest +from .types.asset_service import ListAssetsResponse from .types.asset_service import ListFeedsRequest from .types.asset_service import ListFeedsResponse from .types.asset_service import OutputConfig @@ -48,6 +50,7 @@ from .types.asset_service import UpdateFeedRequest from .types.asset_service import ContentType from .types.assets import Asset +from .types.assets import ConditionEvaluation from .types.assets import IamPolicyAnalysisResult from .types.assets import IamPolicyAnalysisState from .types.assets import IamPolicySearchResult @@ -67,6 +70,7 @@ "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", "BigQueryDestination", + "ConditionEvaluation", "ContentType", "CreateFeedRequest", "DeleteFeedRequest", @@ -82,6 +86,8 @@ "IamPolicyAnalysisResult", "IamPolicyAnalysisState", "IamPolicySearchResult", + "ListAssetsRequest", + "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", "OutputConfig", diff --git a/google/cloud/asset_v1/gapic_metadata.json b/google/cloud/asset_v1/gapic_metadata.json index a80eb281..eebf25a1 100644 --- a/google/cloud/asset_v1/gapic_metadata.json +++ b/google/cloud/asset_v1/gapic_metadata.json @@ -45,6 +45,11 @@ "get_feed" ] }, + "ListAssets": { + "methods": [ + "list_assets" + ] + }, "ListFeeds": { "methods": [ "list_feeds" @@ -105,6 +110,11 @@ "get_feed" ] }, + "ListAssets": { + "methods": [ + "list_assets" + ] + }, "ListFeeds": { "methods": [ "list_feeds" 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 87bc8bc1..b4d9fcc2 100644 --- a/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1/services/asset_service/async_client.py @@ -236,6 +236,98 @@ async def export_assets( # Done; return the response. return response + async def list_assets( + self, + request: asset_service.ListAssetsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListAssetsAsyncPager: + r"""Lists assets with time and resource types and returns + paged results in response. + + Args: + request (:class:`google.cloud.asset_v1.types.ListAssetsRequest`): + The request object. ListAssets request. + parent (:class:`str`): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" + (such as "projects/my-project-id"), or + "projects/[project-number]" (such as "projects/12345"). + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + 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.services.asset_service.pagers.ListAssetsAsyncPager: + ListAssets response. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = asset_service.ListAssetsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_assets, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListAssetsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + async def batch_get_assets_history( self, request: asset_service.BatchGetAssetsHistoryRequest = None, @@ -730,7 +822,7 @@ async def search_all_resources( Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -746,40 +838,48 @@ async def search_all_resources( should not be set. query (:class:`str`): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each - Cloud IAM policy binding, including its members, roles, - and Cloud IAM conditions. The returned Cloud IAM - policies will only contain the bindings that match your - query. To learn more about the IAM policy structure, see - `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose + name is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word + in the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with + a customer-managed encryption key whose name contains + 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. + - ``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 seconds. + - ``updateTime>1609459200`` to find Cloud resources + that were updated after "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain - "Impor" as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" - as a substring in any of the searchable fields. + "Impor" as a prefix of any word in any of the + searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in @@ -794,6 +894,20 @@ async def search_all_resources( `searchable asset types `__. + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type + ends with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ + for all supported regular expression syntax. If the + regular expression does not match any supported asset + type, an INVALID_ARGUMENT error will be returned. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -890,7 +1004,7 @@ async def search_all_iam_policies( Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -909,7 +1023,13 @@ async def search_all_iam_policies( query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified - ``scope``. + ``scope``. Note that the query string is compared + against each Cloud IAM policy binding, including its + members, roles, and Cloud IAM conditions. The returned + Cloud IAM policies will only contain the bindings that + match your query. To learn more about the IAM policy + structure, see `IAM policy + doc `__. Examples: @@ -917,6 +1037,9 @@ async def search_all_iam_policies( that specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that + contain "comp" as a prefix of any word in the + binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note @@ -924,15 +1047,22 @@ async def search_all_iam_policies( to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a + prefix of any word in the role permission. Note that + if callers don't have ``iam.roles.get`` access to a + role's included permissions, policy bindings that + specify this role will be dropped from the search + results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the + project named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain - "por" as a substring in any of the searchable fields - (except for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user diff --git a/google/cloud/asset_v1/services/asset_service/client.py b/google/cloud/asset_v1/services/asset_service/client.py index 40b3fe71..54151fb8 100644 --- a/google/cloud/asset_v1/services/asset_service/client.py +++ b/google/cloud/asset_v1/services/asset_service/client.py @@ -422,6 +422,88 @@ def export_assets( # Done; return the response. return response + def list_assets( + self, + request: asset_service.ListAssetsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListAssetsPager: + r"""Lists assets with time and resource types and returns + paged results in response. + + Args: + request (google.cloud.asset_v1.types.ListAssetsRequest): + The request object. ListAssets request. + parent (str): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" + (such as "projects/my-project-id"), or + "projects/[project-number]" (such as "projects/12345"). + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + 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.services.asset_service.pagers.ListAssetsPager: + ListAssets response. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a asset_service.ListAssetsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, asset_service.ListAssetsRequest): + request = asset_service.ListAssetsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_assets] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListAssetsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + def batch_get_assets_history( self, request: asset_service.BatchGetAssetsHistoryRequest = None, @@ -877,7 +959,7 @@ def search_all_resources( Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -893,40 +975,48 @@ def search_all_resources( should not be set. query (str): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each - Cloud IAM policy binding, including its members, roles, - and Cloud IAM conditions. The returned Cloud IAM - policies will only contain the bindings that match your - query. To learn more about the IAM policy structure, see - `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose + name is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word + in the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with + a customer-managed encryption key whose name contains + 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. + - ``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 seconds. + - ``updateTime>1609459200`` to find Cloud resources + that were updated after "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain - "Impor" as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" - as a substring in any of the searchable fields. + "Impor" as a prefix of any word in any of the + searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in @@ -941,6 +1031,20 @@ def search_all_resources( `searchable asset types `__. + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type + ends with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ + for all supported regular expression syntax. If the + regular expression does not match any supported asset + type, an INVALID_ARGUMENT error will be returned. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1027,7 +1131,7 @@ def search_all_iam_policies( Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -1046,7 +1150,13 @@ def search_all_iam_policies( query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified - ``scope``. + ``scope``. Note that the query string is compared + against each Cloud IAM policy binding, including its + members, roles, and Cloud IAM conditions. The returned + Cloud IAM policies will only contain the bindings that + match your query. To learn more about the IAM policy + structure, see `IAM policy + doc `__. Examples: @@ -1054,6 +1164,9 @@ def search_all_iam_policies( that specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that + contain "comp" as a prefix of any word in the + binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note @@ -1061,15 +1174,22 @@ def search_all_iam_policies( to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a + prefix of any word in the role permission. Note that + if callers don't have ``iam.roles.get`` access to a + role's included permissions, policy bindings that + specify this role will be dropped from the search + results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the + project named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain - "por" as a substring in any of the searchable fields - (except for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user diff --git a/google/cloud/asset_v1/services/asset_service/pagers.py b/google/cloud/asset_v1/services/asset_service/pagers.py index 8db1ae2e..862f5e9b 100644 --- a/google/cloud/asset_v1/services/asset_service/pagers.py +++ b/google/cloud/asset_v1/services/asset_service/pagers.py @@ -28,6 +28,134 @@ from google.cloud.asset_v1.types import assets +class ListAssetsPager: + """A pager for iterating through ``list_assets`` requests. + + This class thinly wraps an initial + :class:`google.cloud.asset_v1.types.ListAssetsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``assets`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListAssets`` requests and continue to iterate + through the ``assets`` field on the + corresponding responses. + + All the usual :class:`google.cloud.asset_v1.types.ListAssetsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., asset_service.ListAssetsResponse], + request: asset_service.ListAssetsRequest, + response: asset_service.ListAssetsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.asset_v1.types.ListAssetsRequest): + The initial request object. + response (google.cloud.asset_v1.types.ListAssetsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = asset_service.ListAssetsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[asset_service.ListAssetsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[assets.Asset]: + for page in self.pages: + yield from page.assets + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListAssetsAsyncPager: + """A pager for iterating through ``list_assets`` requests. + + This class thinly wraps an initial + :class:`google.cloud.asset_v1.types.ListAssetsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``assets`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListAssets`` requests and continue to iterate + through the ``assets`` field on the + corresponding responses. + + All the usual :class:`google.cloud.asset_v1.types.ListAssetsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[asset_service.ListAssetsResponse]], + request: asset_service.ListAssetsRequest, + response: asset_service.ListAssetsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.asset_v1.types.ListAssetsRequest): + The initial request object. + response (google.cloud.asset_v1.types.ListAssetsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = asset_service.ListAssetsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[asset_service.ListAssetsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[assets.Asset]: + async def async_generator(): + async for page in self.pages: + for response in page.assets: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + class SearchAllResourcesPager: """A pager for iterating through ``search_all_resources`` requests. 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 40fdf882..42793ee5 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1/services/asset_service/transports/base.py @@ -170,6 +170,21 @@ def _prep_wrapped_messages(self, client_info): self.export_assets: gapic_v1.method.wrap_method( self.export_assets, default_timeout=60.0, client_info=client_info, ), + self.list_assets: gapic_v1.method.wrap_method( + self.list_assets, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), self.batch_get_assets_history: gapic_v1.method.wrap_method( self.batch_get_assets_history, default_retry=retries.Retry( @@ -301,6 +316,18 @@ def export_assets( ]: raise NotImplementedError() + @property + def list_assets( + self, + ) -> Callable[ + [asset_service.ListAssetsRequest], + Union[ + asset_service.ListAssetsResponse, + Awaitable[asset_service.ListAssetsResponse], + ], + ]: + raise NotImplementedError() + @property def batch_get_assets_history( self, 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 adf72412..6ca9e36a 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc.py @@ -277,6 +277,33 @@ def export_assets( ) return self._stubs["export_assets"] + @property + def list_assets( + self, + ) -> Callable[[asset_service.ListAssetsRequest], asset_service.ListAssetsResponse]: + r"""Return a callable for the list assets method over gRPC. + + Lists assets with time and resource types and returns + paged results in response. + + Returns: + Callable[[~.ListAssetsRequest], + ~.ListAssetsResponse]: + 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 "list_assets" not in self._stubs: + self._stubs["list_assets"] = self.grpc_channel.unary_unary( + "/google.cloud.asset.v1.AssetService/ListAssets", + request_serializer=asset_service.ListAssetsRequest.serialize, + response_deserializer=asset_service.ListAssetsResponse.deserialize, + ) + return self._stubs["list_assets"] + @property def batch_get_assets_history( self, 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 fcfa7d90..96f1af84 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 @@ -284,6 +284,35 @@ def export_assets( ) return self._stubs["export_assets"] + @property + def list_assets( + self, + ) -> Callable[ + [asset_service.ListAssetsRequest], Awaitable[asset_service.ListAssetsResponse] + ]: + r"""Return a callable for the list assets method over gRPC. + + Lists assets with time and resource types and returns + paged results in response. + + Returns: + Callable[[~.ListAssetsRequest], + Awaitable[~.ListAssetsResponse]]: + 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 "list_assets" not in self._stubs: + self._stubs["list_assets"] = self.grpc_channel.unary_unary( + "/google.cloud.asset.v1.AssetService/ListAssets", + request_serializer=asset_service.ListAssetsRequest.serialize, + response_deserializer=asset_service.ListAssetsResponse.deserialize, + ) + return self._stubs["list_assets"] + @property def batch_get_assets_history( self, diff --git a/google/cloud/asset_v1/types/__init__.py b/google/cloud/asset_v1/types/__init__.py index b75ed5e3..600d11c3 100644 --- a/google/cloud/asset_v1/types/__init__.py +++ b/google/cloud/asset_v1/types/__init__.py @@ -32,6 +32,8 @@ GetFeedRequest, IamPolicyAnalysisOutputConfig, IamPolicyAnalysisQuery, + ListAssetsRequest, + ListAssetsResponse, ListFeedsRequest, ListFeedsResponse, OutputConfig, @@ -47,6 +49,7 @@ ) from .assets import ( Asset, + ConditionEvaluation, IamPolicyAnalysisResult, IamPolicyAnalysisState, IamPolicySearchResult, @@ -75,6 +78,8 @@ "GetFeedRequest", "IamPolicyAnalysisOutputConfig", "IamPolicyAnalysisQuery", + "ListAssetsRequest", + "ListAssetsResponse", "ListFeedsRequest", "ListFeedsResponse", "OutputConfig", @@ -88,6 +93,7 @@ "UpdateFeedRequest", "ContentType", "Asset", + "ConditionEvaluation", "IamPolicyAnalysisResult", "IamPolicyAnalysisState", "IamPolicySearchResult", diff --git a/google/cloud/asset_v1/types/asset_service.py b/google/cloud/asset_v1/types/asset_service.py index 26ec00c0..9f6a1854 100644 --- a/google/cloud/asset_v1/types/asset_service.py +++ b/google/cloud/asset_v1/types/asset_service.py @@ -28,6 +28,8 @@ "ContentType", "ExportAssetsRequest", "ExportAssetsResponse", + "ListAssetsRequest", + "ListAssetsResponse", "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", "CreateFeedRequest", @@ -153,6 +155,93 @@ class ExportAssetsResponse(proto.Message): output_result = proto.Field(proto.MESSAGE, number=3, message="OutputResult",) +class ListAssetsRequest(proto.Message): + r"""ListAssets request. + Attributes: + parent (str): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" (such + as "projects/my-project-id"), or "projects/[project-number]" + (such as "projects/12345"). + read_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp to take an asset snapshot. This can + only be set to a timestamp between the current + time and the current time minus 35 days + (inclusive). If not specified, the current time + will be used. Due to delays in resource data + collection and indexing, there is a volatile + window during which running the same query may + get different results. + asset_types (Sequence[str]): + A list of asset types to take a snapshot for. For example: + "compute.googleapis.com/Disk". + + Regular expression is also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type ends + with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ for + all supported regular expression syntax. If the regular + expression does not match any supported asset type, an + INVALID_ARGUMENT error will be returned. + + If specified, only matching assets will be returned, + otherwise, it will snapshot all asset types. See + `Introduction to Cloud Asset + Inventory `__ + for all supported asset types. + content_type (google.cloud.asset_v1.types.ContentType): + Asset content type. If not specified, no + content but the asset name will be returned. + page_size (int): + The maximum number of assets to be returned + in a single response. Default is 100, minimum is + 1, and maximum is 1000. + page_token (str): + The ``next_page_token`` returned from the previous + ``ListAssetsResponse``, or unspecified for the first + ``ListAssetsRequest``. It is a continuation of a prior + ``ListAssets`` call, and the API should return the next page + of assets. + """ + + parent = proto.Field(proto.STRING, number=1,) + read_time = proto.Field(proto.MESSAGE, number=2, message=timestamp_pb2.Timestamp,) + asset_types = proto.RepeatedField(proto.STRING, number=3,) + content_type = proto.Field(proto.ENUM, number=4, enum="ContentType",) + page_size = proto.Field(proto.INT32, number=5,) + page_token = proto.Field(proto.STRING, number=6,) + + +class ListAssetsResponse(proto.Message): + r"""ListAssets response. + Attributes: + read_time (google.protobuf.timestamp_pb2.Timestamp): + Time the snapshot was taken. + assets (Sequence[google.cloud.asset_v1.types.Asset]): + Assets. + next_page_token (str): + Token to retrieve the next page of results. + It expires 72 hours after the page token for the + first page is generated. Set to empty if there + are no remaining results. + """ + + @property + def raw_page(self): + return self + + read_time = proto.Field(proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,) + assets = proto.RepeatedField(proto.MESSAGE, number=2, message=gca_assets.Asset,) + next_page_token = proto.Field(proto.STRING, number=3,) + + class BatchGetAssetsHistoryRequest(proto.Message): r"""Batch get assets history request. Attributes: @@ -356,6 +445,11 @@ class GcsDestination(proto.Message): See `Viewing and Editing Object Metadata `__ for more information. + + If the specified Cloud Storage object already exists and + there is no + `hold `__, + it will be overwritten with the exported result. uri_prefix (str): The uri prefix of all generated Cloud Storage objects. Example: "gs://bucket_name/object_name_prefix". Each object @@ -581,7 +675,7 @@ class SearchAllResourcesRequest(proto.Message): Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -593,38 +687,46 @@ class SearchAllResourcesRequest(proto.Message): "organizations/123456") query (str): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each Cloud - IAM policy binding, including its members, roles, and Cloud - IAM conditions. The returned Cloud IAM policies will only - contain the bindings that match your query. To learn more - about the IAM policy structure, see `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose name + is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word in + the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with a + customer-managed encryption key whose name contains 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. + - ``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 + seconds. + - ``updateTime>1609459200`` to find Cloud resources that + were updated after "2021-01-01 00:00:00 UTC". 1609459200 + is the epoch timestamp of "2021-01-01 00:00:00 UTC" in + seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain "Impor" - as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" as a - substring in any of the searchable fields. + as a prefix of any word in any of the searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in the @@ -633,6 +735,20 @@ class SearchAllResourcesRequest(proto.Message): Optional. A list of asset types that this request searches for. If empty, it will search all the `searchable asset types `__. + + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type ends + with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ for + all supported regular expression syntax. If the regular + expression does not match any supported asset type, an + INVALID_ARGUMENT error will be returned. page_size (int): Optional. The page size for search result pagination. Page size is capped at 500 even if a larger value is given. If @@ -647,16 +763,28 @@ class SearchAllResourcesRequest(proto.Message): the previous response. The values of all other method parameters, must be identical to those in the previous call. order_by (str): - Optional. A comma separated list of fields specifying the + Optional. A comma-separated list of fields specifying the sorting order of the results. The default order is ascending. Add " DESC" after the field name to indicate descending order. Redundant space characters are ignored. - Example: "location DESC, name". Only string fields in the - response are sortable, including ``name``, ``displayName``, - ``description``, ``location``. 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. + Example: "location DESC, name". Only singular primitive + fields in the response are sortable: + + - name + - assetType + - project + - displayName + - description + - location + - kmsKey + - createTime + - 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. """ scope = proto.Field(proto.STRING, number=1,) @@ -698,7 +826,7 @@ class SearchAllIamPoliciesRequest(proto.Message): Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -713,6 +841,12 @@ class SearchAllIamPoliciesRequest(proto.Message): query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified ``scope``. + Note that the query string is compared against each Cloud + IAM policy binding, including its members, roles, and Cloud + IAM conditions. The returned Cloud IAM policies will only + contain the bindings that match your query. To learn more + about the IAM policy structure, see `IAM policy + doc `__. Examples: @@ -720,20 +854,28 @@ class SearchAllIamPoliciesRequest(proto.Message): specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that contain + "comp" as a prefix of any word in the binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note that if callers don't have ``iam.roles.get`` access to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a prefix + of any word in the role permission. Note that if callers + don't have ``iam.roles.get`` access to a role's included + permissions, policy bindings that specify this role will + be dropped from the search results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the project + named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain "por" - as a substring in any of the searchable fields (except - for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". @@ -783,7 +925,7 @@ def raw_page(self): class IamPolicyAnalysisQuery(proto.Message): - r"""IAM policy analysis query message. + r"""## IAM policy analysis query message. Attributes: scope (str): Required. The relative name of the root asset. Only @@ -810,6 +952,9 @@ class IamPolicyAnalysisQuery(proto.Message): analysis. This is optional. options (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.Options): Optional. The query options. + condition_context (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.ConditionContext): + Optional. The hypothetical context for IAM + conditions evaluation. """ class ResourceSelector(proto.Message): @@ -965,11 +1110,29 @@ class Options(proto.Message): output_group_edges = proto.Field(proto.BOOL, number=5,) analyze_service_account_impersonation = proto.Field(proto.BOOL, number=6,) + class ConditionContext(proto.Message): + r"""The IAM conditions context. + Attributes: + access_time (google.protobuf.timestamp_pb2.Timestamp): + The hypothetical access timestamp to evaluate IAM + conditions. Note that this value must not be earlier than + the current time; otherwise, an INVALID_ARGUMENT error will + be returned. + """ + + access_time = proto.Field( + proto.MESSAGE, + number=1, + oneof="TimeContext", + message=timestamp_pb2.Timestamp, + ) + scope = proto.Field(proto.STRING, number=1,) resource_selector = proto.Field(proto.MESSAGE, number=2, message=ResourceSelector,) identity_selector = proto.Field(proto.MESSAGE, number=3, message=IdentitySelector,) access_selector = proto.Field(proto.MESSAGE, number=4, message=AccessSelector,) options = proto.Field(proto.MESSAGE, number=5, message=Options,) + condition_context = proto.Field(proto.MESSAGE, number=6, message=ConditionContext,) class AnalyzeIamPolicyRequest(proto.Message): @@ -1075,11 +1238,16 @@ class GcsDestination(proto.Message): Attributes: uri (str): Required. The uri of the Cloud Storage object. It's the same - uri that is used by gsutil. For example: - "gs://bucket_name/object_name". See [Quickstart: Using the - gsutil tool] - (https://cloud.google.com/storage/docs/quickstart-gsutil) - for examples. + uri that is used by gsutil. Example: + "gs://bucket_name/object_name". See `Viewing and Editing + Object + Metadata `__ + for more information. + + If the specified Cloud Storage object already exists and + there is no + `hold `__, + it will be overwritten with the analysis result. """ uri = proto.Field(proto.STRING, number=1,) diff --git a/google/cloud/asset_v1/types/assets.py b/google/cloud/asset_v1/types/assets.py index f4086a8e..893f9c33 100644 --- a/google/cloud/asset_v1/types/assets.py +++ b/google/cloud/asset_v1/types/assets.py @@ -36,6 +36,7 @@ "ResourceSearchResult", "IamPolicySearchResult", "IamPolicyAnalysisState", + "ConditionEvaluation", "IamPolicyAnalysisResult", }, ) @@ -98,7 +99,8 @@ class Asset(proto.Message): hierarchy `__, a resource outside the Google Cloud resource hierarchy (such as Google Kubernetes Engine clusters and objects), or a policy (e.g. - Cloud IAM policy). See `Supported asset + Cloud IAM policy), or a relationship (e.g. an + INSTANCE_TO_INSTANCEGROUP relationship). See `Supported asset types `__ for more information. @@ -148,7 +150,7 @@ class Asset(proto.Message): service_perimeter (google.identity.accesscontextmanager.v1.service_perimeter_pb2.ServicePerimeter): Please also refer to the `service perimeter user guide `__. - os_inventory (ggoogle.cloud.osconfig_v1.Inventory): + os_inventory (google.cloud.osconfig_v1.Inventory): A representation of runtime OS Inventory information. See `this topic `__ @@ -280,14 +282,40 @@ class ResourceSearchResult(proto.Message): - specify the ``asset_type`` field in your search request. project (str): The project that this resource belongs to, in the form of - projects/{PROJECT_NUMBER}. + projects/{PROJECT_NUMBER}. This field is available when the + resource belongs to a project. - To search against the ``project``: + To search against ``project``: + - use a field query. Example: ``project:12345`` + - use a free text query. Example: ``12345`` - specify the ``scope`` field as this project in your search request. + folders (Sequence[str]): + The folder(s) that this resource belongs to, in the form of + folders/{FOLDER_NUMBER}. This field is available when the + resource belongs to one or more folders. + + To search against ``folders``: + + - use a field query. Example: ``folders:(123 OR 456)`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this folder in your search + request. + organization (str): + The organization that this resource belongs to, in the form + of organizations/{ORGANIZATION_NUMBER}. This field is + available when the resource belongs to an organization. + + To search against ``organization``: + + - use a field query. Example: ``organization:123`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this organization in your + search request. display_name (str): - The display name of this resource. + The display name of this resource. This field is available + only when the resource's proto contains it. To search against the ``display_name``: @@ -295,17 +323,18 @@ class ResourceSearchResult(proto.Message): - use a free text query. Example: ``"My Instance"`` description (str): One or more paragraphs of text description of this resource. - Maximum length could be up to 1M bytes. + Maximum length could be up to 1M bytes. This field is + available only when the resource's proto contains it. To search against the ``description``: - use a field query. Example: - ``description:"*important instance*"`` - - use a free text query. Example: - ``"*important instance*"`` + ``description:"important instance"`` + - use a free text query. Example: ``"important instance"`` location (str): Location can be ``global``, regional like ``us-east1``, or - zonal like ``us-west1-b``. + zonal like ``us-west1-b``. This field is available only when + the resource's proto contains it. To search against the ``location``: @@ -315,7 +344,8 @@ class ResourceSearchResult(proto.Message): Labels associated with this resource. See `Labelling and grouping GCP resources `__ - for more information. + for more information. This field is available only when the + resource's proto contains it. To search against the ``labels``: @@ -333,12 +363,78 @@ class ResourceSearchResult(proto.Message): network tags are a type of annotations used to group GCP resources. See `Labelling GCP resources `__ - for more information. + for more information. This field is available only when the + resource's proto contains it. To search against the ``network_tags``: - use a field query. Example: ``networkTags:internal`` - use a free text query. Example: ``internal`` + kms_key (str): + The Cloud KMS + `CryptoKey `__ + name or + `CryptoKeyVersion `__ + name. This field is available only when the resource's proto + contains it. + + To search against the ``kms_key``: + + - use a field query. Example: ``kmsKey:key`` + - use a free text query. Example: ``key`` + create_time (google.protobuf.timestamp_pb2.Timestamp): + The create timestamp of this resource, at which the resource + was created. The granularity is in seconds. Timestamp.nanos + will always be 0. This field is available only when the + resource's proto contains it. + + To search against ``create_time``: + + - use a field query. + + - value in seconds since unix epoch. Example: + ``createTime > 1609459200`` + - value in date string. Example: + ``createTime > 2021-01-01`` + - value in date-time string (must be quoted). Example: + ``createTime > "2021-01-01T00:00:00"`` + update_time (google.protobuf.timestamp_pb2.Timestamp): + The last update timestamp of this resource, at which the + resource was last modified or deleted. The granularity is in + seconds. Timestamp.nanos will always be 0. This field is + available only when the resource's proto contains it. + + To search against ``update_time``: + + - use a field query. + + - value in seconds since unix epoch. Example: + ``updateTime < 1609459200`` + - value in date string. Example: + ``updateTime < 2021-01-01`` + - value in date-time string (must be quoted). Example: + ``updateTime < "2021-01-01T00:00:00"`` + state (str): + The state of this resource. Different resources types have + different state definitions that are mapped from various + fields of different resource types. This field is available + only when the resource's proto contains it. + + Example: If the resource is an instance provided by Compute + Engine, its state will include PROVISIONING, STAGING, + RUNNING, STOPPING, SUSPENDING, SUSPENDED, REPAIRING, and + TERMINATED. See ``status`` definition in `API + Reference `__. + If the resource is a project provided by Cloud Resource + Manager, its state will include LIFECYCLE_STATE_UNSPECIFIED, + ACTIVE, DELETE_REQUESTED and DELETE_IN_PROGRESS. See + ``lifecycleState`` definition in `API + Reference `__. + + To search against the ``state``: + + - use a field query. Example: ``state:RUNNING`` + - use a free text query. Example: ``RUNNING`` additional_attributes (google.protobuf.struct_pb2.Struct): The additional searchable attributes of this resource. The attributes may vary from one resource type to another. @@ -348,7 +444,7 @@ class ResourceSearchResult(proto.Message): provided by the corresponding GCP service (e.g., Compute Engine). see `API references and supported searchable attributes `__ - for more information. + to see which fields are included. You can search values of these fields through free text search. However, you should not consume the field @@ -361,19 +457,48 @@ class ResourceSearchResult(proto.Message): Example: to search ``additional_attributes = { dnsName: "foobar" }``, you can issue a query ``foobar``. + parent_full_resource_name (str): + The full resource name of this resource's parent, if it has + one. To search against the ``parent_full_resource_name``: + + - use a field query. Example: + ``parentFullResourceName:"project-name"`` + - use a free text query. Example: ``project-name`` + parent_asset_type (str): + The type of this resource's immediate parent, if there is + one. + + To search against the ``parent_asset_type``: + + - use a field query. Example: + ``parentAssetType:"cloudresourcemanager.googleapis.com/Project"`` + - use a free text query. Example: + ``cloudresourcemanager.googleapis.com/Project`` """ name = proto.Field(proto.STRING, number=1,) asset_type = proto.Field(proto.STRING, number=2,) project = proto.Field(proto.STRING, number=3,) + folders = proto.RepeatedField(proto.STRING, number=17,) + organization = proto.Field(proto.STRING, number=18,) display_name = proto.Field(proto.STRING, number=4,) description = proto.Field(proto.STRING, number=5,) location = proto.Field(proto.STRING, number=6,) labels = proto.MapField(proto.STRING, proto.STRING, number=7,) network_tags = proto.RepeatedField(proto.STRING, number=8,) + kms_key = proto.Field(proto.STRING, number=10,) + create_time = proto.Field( + proto.MESSAGE, number=11, message=timestamp_pb2.Timestamp, + ) + update_time = proto.Field( + proto.MESSAGE, number=12, message=timestamp_pb2.Timestamp, + ) + state = proto.Field(proto.STRING, number=13,) additional_attributes = proto.Field( proto.MESSAGE, number=9, message=struct_pb2.Struct, ) + parent_full_resource_name = proto.Field(proto.STRING, number=19,) + parent_asset_type = proto.Field(proto.STRING, number=103,) class IamPolicySearchResult(proto.Message): @@ -399,7 +524,7 @@ class IamPolicySearchResult(proto.Message): set on a resource (like VM instance, Cloud Storage bucket), the project field will indicate the project that contains the resource. If an IAM policy is set on a folder or - orgnization, the project field will be empty. + orgnization, this field will be empty. To search against the ``project``: @@ -492,6 +617,23 @@ class IamPolicyAnalysisState(proto.Message): cause = proto.Field(proto.STRING, number=2,) +class ConditionEvaluation(proto.Message): + r"""The Condition evaluation. + Attributes: + evaluation_value (google.cloud.asset_v1.types.ConditionEvaluation.EvaluationValue): + The evaluation result. + """ + + class EvaluationValue(proto.Enum): + r"""Value of this expression.""" + EVALUATION_VALUE_UNSPECIFIED = 0 + TRUE = 1 + FALSE = 2 + CONDITIONAL = 3 + + evaluation_value = proto.Field(proto.ENUM, number=1, enum=EvaluationValue,) + + class IamPolicyAnalysisResult(proto.Message): r"""IAM Policy analysis result, consisting of one IAM policy binding and derived access control lists. @@ -636,6 +778,10 @@ class AccessControlList(proto.Message): contains the full resource name of a child resource. This field is present only if the output_resource_edges option is enabled in request. + condition_evaluation (google.cloud.asset_v1.types.ConditionEvaluation): + Condition evaluation for this + AccessControlList, if there is a condition + defined in the above IAM policy binding. """ resources = proto.RepeatedField( @@ -647,6 +793,9 @@ class AccessControlList(proto.Message): resource_edges = proto.RepeatedField( proto.MESSAGE, number=3, message="IamPolicyAnalysisResult.Edge", ) + condition_evaluation = proto.Field( + proto.MESSAGE, number=4, message="ConditionEvaluation", + ) class IdentityList(proto.Message): r"""The identities and group edges. diff --git a/scripts/fixup_asset_v1_keywords.py b/scripts/fixup_asset_v1_keywords.py index b0cdcf3f..cfef8db5 100644 --- a/scripts/fixup_asset_v1_keywords.py +++ b/scripts/fixup_asset_v1_keywords.py @@ -46,6 +46,7 @@ class assetCallTransformer(cst.CSTTransformer): 'delete_feed': ('name', ), 'export_assets': ('parent', 'output_config', 'read_time', 'asset_types', 'content_type', ), 'get_feed': ('name', ), + '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', ), 'search_all_resources': ('scope', 'query', 'asset_types', 'page_size', 'page_token', 'order_by', ), diff --git a/tests/unit/gapic/asset_v1/test_asset_service.py b/tests/unit/gapic/asset_v1/test_asset_service.py index 87fadf1a..d6140d64 100644 --- a/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1/test_asset_service.py @@ -597,6 +597,318 @@ async def test_export_assets_field_headers_async(): assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] +def test_list_assets( + transport: str = "grpc", request_type=asset_service.ListAssetsRequest +): + 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.list_assets), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse( + next_page_token="next_page_token_value", + ) + response = client.list_assets(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.ListAssetsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAssetsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_assets_from_dict(): + test_list_assets(request_type=dict) + + +def test_list_assets_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.list_assets), "__call__") as call: + client.list_assets() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.ListAssetsRequest() + + +@pytest.mark.asyncio +async def test_list_assets_async( + transport: str = "grpc_asyncio", request_type=asset_service.ListAssetsRequest +): + 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.list_assets), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + asset_service.ListAssetsResponse(next_page_token="next_page_token_value",) + ) + response = await client.list_assets(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.ListAssetsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAssetsAsyncPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_assets_async_from_dict(): + await test_list_assets_async(request_type=dict) + + +def test_list_assets_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.ListAssetsRequest() + + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + call.return_value = asset_service.ListAssetsResponse() + client.list_assets(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", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_assets_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.ListAssetsRequest() + + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + asset_service.ListAssetsResponse() + ) + await client.list_assets(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", "parent=parent/value",) in kw["metadata"] + + +def test_list_assets_flattened(): + client = AssetServiceClient(credentials=ga_credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_assets(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == "parent_value" + + +def test_list_assets_flattened_error(): + client = AssetServiceClient(credentials=ga_credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_assets( + asset_service.ListAssetsRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_assets_flattened_async(): + client = AssetServiceAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + asset_service.ListAssetsResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_assets(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_list_assets_flattened_error_async(): + client = AssetServiceAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_assets( + asset_service.ListAssetsRequest(), parent="parent_value", + ) + + +def test_list_assets_pager(): + client = AssetServiceClient(credentials=ga_credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[assets.Asset(), assets.Asset(), assets.Asset(),], + next_page_token="abc", + ), + asset_service.ListAssetsResponse(assets=[], next_page_token="def",), + asset_service.ListAssetsResponse( + assets=[assets.Asset(),], next_page_token="ghi", + ), + asset_service.ListAssetsResponse(assets=[assets.Asset(), assets.Asset(),],), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_assets(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, assets.Asset) for i in results) + + +def test_list_assets_pages(): + client = AssetServiceClient(credentials=ga_credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[assets.Asset(), assets.Asset(), assets.Asset(),], + next_page_token="abc", + ), + asset_service.ListAssetsResponse(assets=[], next_page_token="def",), + asset_service.ListAssetsResponse( + assets=[assets.Asset(),], next_page_token="ghi", + ), + asset_service.ListAssetsResponse(assets=[assets.Asset(), assets.Asset(),],), + RuntimeError, + ) + pages = list(client.list_assets(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_assets_async_pager(): + client = AssetServiceAsyncClient(credentials=ga_credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[assets.Asset(), assets.Asset(), assets.Asset(),], + next_page_token="abc", + ), + asset_service.ListAssetsResponse(assets=[], next_page_token="def",), + asset_service.ListAssetsResponse( + assets=[assets.Asset(),], next_page_token="ghi", + ), + asset_service.ListAssetsResponse(assets=[assets.Asset(), assets.Asset(),],), + RuntimeError, + ) + async_pager = await client.list_assets(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, assets.Asset) for i in responses) + + +@pytest.mark.asyncio +async def test_list_assets_async_pages(): + client = AssetServiceAsyncClient(credentials=ga_credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[assets.Asset(), assets.Asset(), assets.Asset(),], + next_page_token="abc", + ), + asset_service.ListAssetsResponse(assets=[], next_page_token="def",), + asset_service.ListAssetsResponse( + assets=[assets.Asset(),], next_page_token="ghi", + ), + asset_service.ListAssetsResponse(assets=[assets.Asset(), assets.Asset(),],), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_assets(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + def test_batch_get_assets_history( transport: str = "grpc", request_type=asset_service.BatchGetAssetsHistoryRequest ): @@ -2912,6 +3224,7 @@ def test_asset_service_base_transport(): # raise NotImplementedError. methods = ( "export_assets", + "list_assets", "batch_get_assets_history", "create_feed", "get_feed",