1# -*- coding: utf-8 -*- # 2# Copyright 2018 Google LLC. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Shared utilities for access the CloudAsset API client.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import unicode_literals 20 21from apitools.base.py import encoding 22from apitools.base.py import list_pager 23 24from googlecloudsdk.api_lib.util import apis 25from googlecloudsdk.calliope import exceptions as gcloud_exceptions 26from googlecloudsdk.command_lib.asset import utils as asset_utils 27from googlecloudsdk.command_lib.util.apis import arg_utils 28from googlecloudsdk.command_lib.util.args import repeated 29from googlecloudsdk.core import exceptions as core_exceptions 30from googlecloudsdk.core import log 31from googlecloudsdk.core.util import times 32 33API_NAME = 'cloudasset' 34DEFAULT_API_VERSION = 'v1' 35V1P1BETA1_API_VERSION = 'v1p1beta1' 36V1P4ALPHA1_API_VERSION = 'v1p4alpha1' 37V1P4BETA1_API_VERSION = 'v1p4beta1' 38V1P5BETA1_API_VERSION = 'v1p5beta1' 39V1P7BETA1_API_VERSION = 'v1p7beta1' 40_HEADERS = { 41 'Content-Type': 'application/x-www-form-urlencoded', 42 'X-HTTP-Method-Override': 'GET' 43} 44_HTTP_ERROR_FORMAT = ('HTTP request failed with status code {}. ' 45 'Response content: {}') 46# A dictionary that captures version differences for IAM Policy Analyzer. 47_IAM_POLICY_ANALYZER_VERSION_DICT_JSON = { 48 V1P4ALPHA1_API_VERSION: { 49 'resource_selector': 'resourceSelector', 50 'identity_selector': 'identitySelector', 51 'access_selector': 'accessSelector', 52 'options': 'options', 53 }, 54 V1P4BETA1_API_VERSION: { 55 'resource_selector': 'analysisQuery_resourceSelector', 56 'identity_selector': 'analysisQuery_identitySelector', 57 'access_selector': 'analysisQuery_accessSelector', 58 'options': 'options', 59 }, 60 DEFAULT_API_VERSION: { 61 'resource_selector': 'analysisQuery_resourceSelector', 62 'identity_selector': 'analysisQuery_identitySelector', 63 'access_selector': 'analysisQuery_accessSelector', 64 'options': 'analysisQuery_options', 65 }, 66} 67 68 69class MessageDecodeError(core_exceptions.Error): 70 """Error raised when a failure to decode a message occurs.""" 71 72 73def GetMessages(version=DEFAULT_API_VERSION): 74 """Import and return the cloudasset messages module. 75 76 Args: 77 version: the API version 78 79 Returns: 80 cloudasset message module. 81 """ 82 return apis.GetMessagesModule(API_NAME, version) 83 84 85def GetClient(version=DEFAULT_API_VERSION): 86 """Import and return the cloudasset client module. 87 88 Args: 89 version: the API version 90 91 Returns: 92 cloudasset API client module. 93 """ 94 return apis.GetClientInstance(API_NAME, version) 95 96 97def ContentTypeTranslation(content_type): 98 """Translate content type from gcloud format to API format. 99 100 Args: 101 content_type: the gcloud format of content_type 102 103 Returns: 104 cloudasset API format of content_type. 105 """ 106 if content_type == 'resource': 107 return 'RESOURCE' 108 if content_type == 'iam-policy': 109 return 'IAM_POLICY' 110 if content_type == 'org-policy': 111 return 'ORG_POLICY' 112 if content_type == 'access-policy': 113 return 'ACCESS_POLICY' 114 if content_type == 'os-inventory': 115 return 'OS_INVENTORY' 116 if content_type == 'relationship': 117 return 'RELATIONSHIP' 118 return 'CONTENT_TYPE_UNSPECIFIED' 119 120 121def PartitionKeyTranslation(partition_key): 122 if partition_key == 'read-time': 123 return 'READ_TIME' 124 if partition_key == 'request-time': 125 return 'REQUEST_TIME' 126 return 'PARTITION_KEY_UNSPECIFIED' 127 128 129def MakeGetAssetsHistoryHttpRequests(args, 130 service, 131 api_version=DEFAULT_API_VERSION): 132 """Manually make the get assets history request.""" 133 messages = GetMessages(api_version) 134 135 encoding.AddCustomJsonFieldMapping( 136 messages.CloudassetBatchGetAssetsHistoryRequest, 137 'readTimeWindow_startTime', 'readTimeWindow.startTime') 138 encoding.AddCustomJsonFieldMapping( 139 messages.CloudassetBatchGetAssetsHistoryRequest, 'readTimeWindow_endTime', 140 'readTimeWindow.endTime') 141 142 content_type = arg_utils.ChoiceToEnum( 143 args.content_type, messages.CloudassetBatchGetAssetsHistoryRequest 144 .ContentTypeValueValuesEnum) 145 parent = asset_utils.GetParentNameForGetHistory(args.organization, 146 args.project) 147 start_time = times.FormatDateTime(args.start_time) 148 end_time = None 149 if args.IsSpecified('end_time'): 150 end_time = times.FormatDateTime(args.end_time) 151 152 response = service.BatchGetAssetsHistory( 153 messages.CloudassetBatchGetAssetsHistoryRequest( 154 assetNames=args.asset_names, 155 contentType=content_type, 156 parent=parent, 157 readTimeWindow_endTime=end_time, 158 readTimeWindow_startTime=start_time, 159 )) 160 161 for asset in response.assets: 162 yield asset 163 164 165def _RenderAnalysisforAnalyzeIamPolicy(analysis): 166 """Renders the analysis query and results of the AnalyzeIamPolicy request.""" 167 168 for analysis_result in analysis.analysisResults: 169 entry = {} 170 171 policy = { 172 'attachedResource': analysis_result.attachedResourceFullName, 173 'binding': analysis_result.iamBinding, 174 } 175 entry['policy'] = policy 176 177 entry['ACLs'] = [] 178 for acl in analysis_result.accessControlLists: 179 acls = {} 180 acls['identities'] = analysis_result.identityList.identities 181 acls['accesses'] = acl.accesses 182 acls['resources'] = acl.resources 183 entry['ACLs'].append(acls) 184 185 yield entry 186 187 188def _RenderResponseforAnalyzeIamPolicy(response, 189 analyze_service_account_impersonation): 190 """Renders the response of the AnalyzeIamPolicy request.""" 191 192 if response.fullyExplored: 193 msg = 'Your analysis request is fully explored. ' 194 else: 195 msg = ('Your analysis request is NOT fully explored. You can use the ' 196 '--show-response option to see the unexplored part. ') 197 198 has_results = False 199 if response.mainAnalysis.analysisResults: 200 has_results = True 201 if (not has_results) and analyze_service_account_impersonation: 202 for sa_impersonation_analysis in response.serviceAccountImpersonationAnalysis: 203 if sa_impersonation_analysis.analysisResults: 204 has_results = True 205 break 206 207 if not has_results: 208 msg += 'No matching ACL is found.' 209 else: 210 msg += ('The ACLs matching your requests are listed per IAM policy binding' 211 ', so there could be duplications.') 212 213 for entry in _RenderAnalysisforAnalyzeIamPolicy(response.mainAnalysis): 214 yield entry 215 216 if analyze_service_account_impersonation: 217 for analysis in response.serviceAccountImpersonationAnalysis: 218 title = { 219 'Service Account Impersonation Analysis Query': analysis.analysisQuery 220 } 221 yield title 222 for entry in _RenderAnalysisforAnalyzeIamPolicy(analysis): 223 yield entry 224 225 log.status.Print(msg) 226 227 228def MakeAnalyzeIamPolicyHttpRequests(args, 229 service, 230 messages, 231 api_version=V1P4ALPHA1_API_VERSION): 232 """Manually make the analyze IAM policy request.""" 233 if api_version == V1P4ALPHA1_API_VERSION: 234 folder = None 235 project = None 236 else: 237 folder = args.folder 238 project = args.project 239 240 parent = asset_utils.GetParentNameForAnalyzeIamPolicy(args.organization, 241 project, folder) 242 243 full_resource_name = args.full_resource_name if args.IsSpecified( 244 'full_resource_name') else None 245 246 identity = args.identity if args.IsSpecified('identity') else None 247 248 roles = args.roles if args.IsSpecified('roles') else [] 249 250 permissions = args.permissions if args.IsSpecified('permissions') else [] 251 252 expand_groups = args.expand_groups if args.expand_groups else None 253 254 expand_resources = args.expand_resources if args.expand_resources else None 255 256 expand_roles = args.expand_roles if args.expand_roles else None 257 258 output_resource_edges = None 259 if args.output_resource_edges: 260 if (api_version == V1P4BETA1_API_VERSION or 261 api_version == DEFAULT_API_VERSION) and (not args.show_response): 262 raise gcloud_exceptions.InvalidArgumentException( 263 '--output-resource-edges', 264 'Must be set together with --show-response to take effect.') 265 output_resource_edges = args.output_resource_edges 266 267 output_group_edges = None 268 if args.output_group_edges: 269 if (api_version == V1P4BETA1_API_VERSION or 270 api_version == DEFAULT_API_VERSION) and (not args.show_response): 271 raise gcloud_exceptions.InvalidArgumentException( 272 '--output-group-edges', 273 'Must be set together with --show-response to take effect.') 274 output_group_edges = args.output_group_edges 275 276 output_partial_result_before_timeout = None 277 if api_version == V1P4ALPHA1_API_VERSION and args.IsSpecified( 278 'output_partial_result_before_timeout'): 279 output_partial_result_before_timeout = args.output_partial_result_before_timeout 280 281 execution_timeout = None 282 if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION 283 ) and args.IsSpecified('execution_timeout'): 284 execution_timeout = str(args.execution_timeout) + 's' 285 286 analyze_service_account_impersonation = None 287 if api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION: 288 analyze_service_account_impersonation = args.analyze_service_account_impersonation 289 290 if api_version == V1P4ALPHA1_API_VERSION: 291 return service.AnalyzeIamPolicy( 292 messages.CloudassetAnalyzeIamPolicyRequest( 293 accessSelector_permissions=permissions, 294 accessSelector_roles=roles, 295 identitySelector_identity=identity, 296 options_expandGroups=expand_groups, 297 options_expandResources=expand_resources, 298 options_expandRoles=expand_roles, 299 options_outputGroupEdges=output_group_edges, 300 options_outputPartialResultBeforeTimeout=output_partial_result_before_timeout, 301 options_outputResourceEdges=output_resource_edges, 302 parent=parent, 303 resourceSelector_fullResourceName=full_resource_name, 304 )) 305 elif api_version == V1P4BETA1_API_VERSION: 306 response = service.AnalyzeIamPolicy( 307 messages.CloudassetAnalyzeIamPolicyRequest( 308 analysisQuery_accessSelector_permissions=permissions, 309 analysisQuery_accessSelector_roles=roles, 310 analysisQuery_identitySelector_identity=identity, 311 analysisQuery_resourceSelector_fullResourceName=full_resource_name, 312 options_analyzeServiceAccountImpersonation=analyze_service_account_impersonation, 313 options_executionTimeout=execution_timeout, 314 options_expandGroups=expand_groups, 315 options_expandResources=expand_resources, 316 options_expandRoles=expand_roles, 317 options_outputGroupEdges=output_group_edges, 318 options_outputResourceEdges=output_resource_edges, 319 parent=parent, 320 )) 321 else: 322 response = service.AnalyzeIamPolicy( 323 messages.CloudassetAnalyzeIamPolicyRequest( 324 analysisQuery_accessSelector_permissions=permissions, 325 analysisQuery_accessSelector_roles=roles, 326 analysisQuery_identitySelector_identity=identity, 327 analysisQuery_options_analyzeServiceAccountImpersonation=analyze_service_account_impersonation, 328 analysisQuery_options_expandGroups=expand_groups, 329 analysisQuery_options_expandResources=expand_resources, 330 analysisQuery_options_expandRoles=expand_roles, 331 analysisQuery_options_outputGroupEdges=output_group_edges, 332 analysisQuery_options_outputResourceEdges=output_resource_edges, 333 analysisQuery_resourceSelector_fullResourceName=full_resource_name, 334 executionTimeout=execution_timeout, 335 scope=parent, 336 )) 337 if not args.show_response: 338 return _RenderResponseforAnalyzeIamPolicy( 339 response, analyze_service_account_impersonation) 340 return response 341 342 343class AnalyzeIamPolicyClient(object): 344 """Client for IAM policy analysis.""" 345 346 def __init__(self, api_version=V1P4ALPHA1_API_VERSION): 347 self.api_version = api_version 348 self.client = GetClient(api_version) 349 350 if api_version == DEFAULT_API_VERSION: 351 self.service = self.client.v1 352 elif api_version == V1P4BETA1_API_VERSION: 353 self.service = self.client.v1p4beta1 354 else: 355 self.service = self.client.v1p4alpha1 356 357 def Analyze(self, args): 358 """Calls MakeAnalyzeIamPolicy method.""" 359 messages = self.EncodeMessages(args) 360 return MakeAnalyzeIamPolicyHttpRequests(args, self.service, messages, 361 self.api_version) 362 363 def EncodeMessages(self, args): 364 """Adds custom encoding for MakeAnalyzeIamPolicy request.""" 365 messages = GetMessages(self.api_version) 366 367 def AddCustomJsonFieldMapping(prefix, suffix): 368 field = _IAM_POLICY_ANALYZER_VERSION_DICT_JSON[ 369 self.api_version][prefix] + suffix 370 encoding.AddCustomJsonFieldMapping( 371 messages.CloudassetAnalyzeIamPolicyRequest, 372 field, 373 field.replace('_', '.'), 374 ) 375 376 AddCustomJsonFieldMapping('resource_selector', '_fullResourceName') 377 AddCustomJsonFieldMapping('identity_selector', '_identity') 378 AddCustomJsonFieldMapping('access_selector', '_roles') 379 AddCustomJsonFieldMapping('access_selector', '_permissions') 380 AddCustomJsonFieldMapping('options', '_expandGroups') 381 AddCustomJsonFieldMapping('options', '_expandResources') 382 AddCustomJsonFieldMapping('options', '_expandRoles') 383 AddCustomJsonFieldMapping('options', '_outputResourceEdges') 384 AddCustomJsonFieldMapping('options', '_outputGroupEdges') 385 386 if self.api_version == V1P4ALPHA1_API_VERSION and args.IsSpecified( 387 'output_partial_result_before_timeout'): 388 AddCustomJsonFieldMapping('options', '_outputPartialResultBeforeTimeout') 389 390 if self.api_version == V1P4BETA1_API_VERSION and args.IsSpecified( 391 'execution_timeout'): 392 AddCustomJsonFieldMapping('options', '_executionTimeout') 393 394 if self.api_version == V1P4BETA1_API_VERSION or self.api_version == DEFAULT_API_VERSION: 395 AddCustomJsonFieldMapping('options', 396 '_analyzeServiceAccountImpersonation') 397 398 return messages 399 400 401class AssetExportClient(object): 402 """Client for export asset.""" 403 404 def __init__(self, parent, api_version=DEFAULT_API_VERSION): 405 self.parent = parent 406 self.message_module = GetMessages(api_version) 407 if api_version == V1P7BETA1_API_VERSION: 408 self.service = GetClient(api_version).v1p7beta1 409 else: 410 self.service = GetClient(api_version).v1 411 self.api_version = api_version 412 413 def Export(self, args): 414 """Export assets with the asset export method.""" 415 content_type = ContentTypeTranslation(args.content_type) 416 partition_key = PartitionKeyTranslation(args.partition_key) 417 partition_key = getattr( 418 self.message_module.PartitionSpec.PartitionKeyValueValuesEnum, 419 partition_key) 420 if args.output_path or args.output_path_prefix: 421 output_config = self.message_module.OutputConfig( 422 gcsDestination=self.message_module.GcsDestination( 423 uri=args.output_path, uriPrefix=args.output_path_prefix)) 424 else: 425 source_ref = args.CONCEPTS.bigquery_table.Parse() 426 output_config = self.message_module.OutputConfig( 427 bigqueryDestination=self.message_module.BigQueryDestination( 428 dataset='projects/' + source_ref.projectId + '/datasets/' + 429 source_ref.datasetId, 430 table=source_ref.tableId, 431 force=args.force_, 432 partitionSpec=self.message_module.PartitionSpec( 433 partitionKey=partition_key), 434 separateTablesPerAssetType=args.per_type_)) 435 snapshot_time = None 436 if args.snapshot_time: 437 snapshot_time = times.FormatDateTime(args.snapshot_time) 438 if (self.api_version == V1P7BETA1_API_VERSION and 439 content_type == 'RELATIONSHIP'): 440 content_type = getattr( 441 self.message_module.ExportAssetsRequest.ContentTypeValueValuesEnum, 442 content_type) 443 export_assets_request = self.message_module.ExportAssetsRequest( 444 assetTypes=args.asset_types, 445 contentType=content_type, 446 outputConfig=output_config, 447 readTime=snapshot_time, 448 relationshipTypes=args.relationship_types) 449 elif content_type == 'RELATIONSHIP': 450 raise gcloud_exceptions.InvalidArgumentException('Export relationship' 451 ' not supported') 452 else: 453 content_type = getattr( 454 self.message_module.ExportAssetsRequest.ContentTypeValueValuesEnum, 455 content_type) 456 export_assets_request = self.message_module.ExportAssetsRequest( 457 assetTypes=args.asset_types, 458 contentType=content_type, 459 outputConfig=output_config, 460 readTime=snapshot_time) 461 request_message = self.message_module.CloudassetExportAssetsRequest( 462 parent=self.parent, exportAssetsRequest=export_assets_request) 463 operation = self.service.ExportAssets(request_message) 464 return operation 465 466 467class AssetFeedClient(object): 468 """Client for asset feed.""" 469 470 def __init__(self, parent, api_version=DEFAULT_API_VERSION): 471 self.parent = parent 472 self.message_module = GetMessages(api_version) 473 self.service = GetClient(api_version).feeds 474 475 def Create(self, args): 476 """Create a feed.""" 477 content_type = ContentTypeTranslation(args.content_type) 478 content_type = getattr(self.message_module.Feed.ContentTypeValueValuesEnum, 479 content_type) 480 feed_output_config = self.message_module.FeedOutputConfig( 481 pubsubDestination=self.message_module.PubsubDestination( 482 topic=args.pubsub_topic)) 483 feed_condition = self.message_module.Expr( 484 expression=args.condition_expression, 485 title=args.condition_title, 486 description=args.condition_description) 487 feed = self.message_module.Feed( 488 assetNames=args.asset_names, 489 assetTypes=args.asset_types, 490 contentType=content_type, 491 feedOutputConfig=feed_output_config, 492 condition=feed_condition) 493 create_feed_request = self.message_module.CreateFeedRequest( 494 feed=feed, feedId=args.feed) 495 request_message = self.message_module.CloudassetFeedsCreateRequest( 496 parent=self.parent, createFeedRequest=create_feed_request) 497 return self.service.Create(request_message) 498 499 def Describe(self, args): 500 """Describe a feed.""" 501 request_message = self.message_module.CloudassetFeedsGetRequest( 502 name='{}/feeds/{}'.format(self.parent, args.feed)) 503 return self.service.Get(request_message) 504 505 def Delete(self, args): 506 """Delete a feed.""" 507 request_message = self.message_module.CloudassetFeedsDeleteRequest( 508 name='{}/feeds/{}'.format(self.parent, args.feed)) 509 self.service.Delete(request_message) 510 511 def List(self): 512 """List feeds under a parent.""" 513 request_message = self.message_module.CloudassetFeedsListRequest( 514 parent=self.parent) 515 return self.service.List(request_message) 516 517 def Update(self, args): 518 """Update a feed.""" 519 update_masks = [] 520 content_type = ContentTypeTranslation(args.content_type) 521 content_type = getattr(self.message_module.Feed.ContentTypeValueValuesEnum, 522 content_type) 523 feed_name = '{}/feeds/{}'.format(self.parent, args.feed) 524 if args.content_type or args.clear_content_type: 525 update_masks.append('content_type') 526 if args.pubsub_topic: 527 update_masks.append('feed_output_config.pubsub_destination.topic') 528 if args.condition_expression or args.clear_condition_expression: 529 update_masks.append('condition.expression') 530 if args.condition_title or args.clear_condition_title: 531 update_masks.append('condition.title') 532 if args.condition_description or args.clear_condition_description: 533 update_masks.append('condition.description') 534 asset_names, asset_types = self.UpdateAssetNamesAndTypes( 535 args, feed_name, update_masks) 536 update_mask = ','.join(update_masks) 537 feed_output_config = self.message_module.FeedOutputConfig( 538 pubsubDestination=self.message_module.PubsubDestination( 539 topic=args.pubsub_topic)) 540 feed_condition = self.message_module.Expr( 541 expression=args.condition_expression, 542 title=args.condition_title, 543 description=args.condition_description) 544 feed = self.message_module.Feed( 545 assetNames=asset_names, 546 assetTypes=asset_types, 547 contentType=content_type, 548 feedOutputConfig=feed_output_config, 549 condition=feed_condition) 550 update_feed_request = self.message_module.UpdateFeedRequest( 551 feed=feed, updateMask=update_mask) 552 request_message = self.message_module.CloudassetFeedsPatchRequest( 553 name=feed_name, updateFeedRequest=update_feed_request) 554 return self.service.Patch(request_message) 555 556 def UpdateAssetNamesAndTypes(self, args, feed_name, update_masks): 557 """Get Updated assetNames and assetTypes.""" 558 feed = self.service.Get( 559 self.message_module.CloudassetFeedsGetRequest(name=feed_name)) 560 asset_names = repeated.ParsePrimitiveArgs(args, 'asset_names', 561 lambda: feed.assetNames) 562 if asset_names is not None: 563 update_masks.append('asset_names') 564 else: 565 asset_names = [] 566 asset_types = repeated.ParsePrimitiveArgs(args, 'asset_types', 567 lambda: feed.assetTypes) 568 if asset_types is not None: 569 update_masks.append('asset_types') 570 else: 571 asset_types = [] 572 return asset_names, asset_types 573 574 575class AssetSearchClient(object): 576 """Client for search assets.""" 577 578 _DEFAULT_PAGE_SIZE = 20 579 580 def __init__(self, api_version): 581 self.message_module = GetMessages(api_version) 582 if api_version == V1P1BETA1_API_VERSION: 583 self.resource_service = GetClient(api_version).resources 584 self.search_all_resources_method = 'SearchAll' 585 self.search_all_resources_request = self.message_module.CloudassetResourcesSearchAllRequest 586 self.policy_service = GetClient(api_version).iamPolicies 587 self.search_all_iam_policies_method = 'SearchAll' 588 self.search_all_iam_policies_request = self.message_module.CloudassetIamPoliciesSearchAllRequest 589 else: 590 self.resource_service = GetClient(api_version).v1 591 self.search_all_resources_method = 'SearchAllResources' 592 self.search_all_resources_request = self.message_module.CloudassetSearchAllResourcesRequest 593 self.policy_service = GetClient(api_version).v1 594 self.search_all_iam_policies_method = 'SearchAllIamPolicies' 595 self.search_all_iam_policies_request = self.message_module.CloudassetSearchAllIamPoliciesRequest 596 597 def SearchAllResources(self, args): 598 """Calls SearchAllResources method.""" 599 request = self.search_all_resources_request( 600 scope=asset_utils.GetDefaultScopeIfEmpty(args), 601 query=args.query, 602 assetTypes=args.asset_types, 603 orderBy=args.order_by) 604 return list_pager.YieldFromList( 605 self.resource_service, 606 request, 607 method=self.search_all_resources_method, 608 field='results', 609 batch_size=args.page_size or self._DEFAULT_PAGE_SIZE, 610 batch_size_attribute='pageSize', 611 current_token_attribute='pageToken', 612 next_token_attribute='nextPageToken') 613 614 def SearchAllIamPolicies(self, args): 615 """Calls SearchAllIamPolicies method.""" 616 request = self.search_all_iam_policies_request( 617 scope=asset_utils.GetDefaultScopeIfEmpty(args), query=args.query) 618 return list_pager.YieldFromList( 619 self.policy_service, 620 request, 621 method=self.search_all_iam_policies_method, 622 field='results', 623 batch_size=args.page_size or self._DEFAULT_PAGE_SIZE, 624 batch_size_attribute='pageSize', 625 current_token_attribute='pageToken', 626 next_token_attribute='nextPageToken') 627 628 629class AssetListClient(object): 630 """Client for list assets.""" 631 632 def __init__(self, parent, api_version=V1P5BETA1_API_VERSION): 633 self.parent = parent 634 self.message_module = GetMessages(api_version) 635 self.service = GetClient(api_version).assets 636 637 def List(self, args, do_filter=False): 638 """List assets with the asset list method.""" 639 snapshot_time = None 640 if args.snapshot_time: 641 snapshot_time = times.FormatDateTime(args.snapshot_time) 642 content_type = ContentTypeTranslation(args.content_type) 643 list_assets_request = self.message_module.CloudassetAssetsListRequest( 644 parent=self.parent, 645 contentType=getattr( 646 self.message_module.CloudassetAssetsListRequest 647 .ContentTypeValueValuesEnum, content_type), 648 assetTypes=args.asset_types, 649 readTime=snapshot_time) 650 return list_pager.YieldFromList( 651 self.service, 652 list_assets_request, 653 field='assets', 654 limit=args.limit, 655 batch_size=args.page_size, 656 batch_size_attribute='pageSize', 657 current_token_attribute='pageToken', 658 next_token_attribute='nextPageToken', 659 predicate=args.filter_func if do_filter else None) 660 661 662class AssetOperationClient(object): 663 """Client for operations.""" 664 665 def __init__(self, api_version=DEFAULT_API_VERSION): 666 self.service = GetClient(api_version).operations 667 self.message = GetMessages(api_version).CloudassetOperationsGetRequest 668 669 def Get(self, name): 670 request = self.message(name=name) 671 return self.service.Get(request) 672 673 674class GetHistoryClient(object): 675 """Client for get history assets.""" 676 677 def __init__(self, api_version=DEFAULT_API_VERSION): 678 self.api_version = api_version 679 self.client = GetClient(api_version) 680 self.service = self.client.v1 681 682 def GetHistory(self, args): 683 return MakeGetAssetsHistoryHttpRequests(args, self.service, 684 self.api_version) 685 686 687class IamPolicyAnalysisLongrunningClient(object): 688 """Client for analyze IAM policy asynchronously.""" 689 690 def __init__(self, api_version=DEFAULT_API_VERSION): 691 self.message_module = GetMessages(api_version) 692 if api_version == V1P4BETA1_API_VERSION: 693 self.service = GetClient(api_version).v1p4beta1 694 else: 695 self.service = GetClient(api_version).v1 696 697 def Analyze(self, scope, args, api_version=DEFAULT_API_VERSION): 698 """Analyze IAM Policy asynchronously.""" 699 analysis_query = self.message_module.IamPolicyAnalysisQuery() 700 if api_version == V1P4BETA1_API_VERSION: 701 analysis_query.parent = scope 702 else: 703 analysis_query.scope = scope 704 if args.IsSpecified('full_resource_name'): 705 analysis_query.resourceSelector = self.message_module.ResourceSelector( 706 fullResourceName=args.full_resource_name) 707 if args.IsSpecified('identity'): 708 analysis_query.identitySelector = self.message_module.IdentitySelector( 709 identity=args.identity) 710 if args.IsSpecified('roles') or args.IsSpecified('permissions'): 711 analysis_query.accessSelector = self.message_module.AccessSelector() 712 if args.IsSpecified('roles'): 713 analysis_query.accessSelector.roles.extend(args.roles) 714 if args.IsSpecified('permissions'): 715 analysis_query.accessSelector.permissions.extend(args.permissions) 716 717 output_config = None 718 if api_version == V1P4BETA1_API_VERSION: 719 output_config = self.message_module.IamPolicyAnalysisOutputConfig( 720 gcsDestination=self.message_module.GcsDestination( 721 uri=args.output_path)) 722 else: 723 if args.gcs_output_path: 724 output_config = self.message_module.IamPolicyAnalysisOutputConfig( 725 gcsDestination=self.message_module.GoogleCloudAssetV1GcsDestination( 726 uri=args.gcs_output_path)) 727 else: 728 output_config = self.message_module.IamPolicyAnalysisOutputConfig( 729 bigqueryDestination=self.message_module 730 .GoogleCloudAssetV1BigQueryDestination( 731 dataset=args.bigquery_dataset, 732 tablePrefix=args.bigquery_table_prefix)) 733 if args.IsSpecified('bigquery_partition_key'): 734 output_config.bigqueryDestination.partitionKey = getattr( 735 self.message_module.GoogleCloudAssetV1BigQueryDestination 736 .PartitionKeyValueValuesEnum, args.bigquery_partition_key) 737 if args.IsSpecified('bigquery_write_disposition'): 738 output_config.bigqueryDestination.writeDisposition = args.bigquery_write_disposition 739 740 options = self.message_module.Options() 741 if args.expand_groups: 742 options.expandGroups = args.expand_groups 743 if args.expand_resources: 744 options.expandResources = args.expand_resources 745 if args.expand_roles: 746 options.expandRoles = args.expand_roles 747 if args.output_resource_edges: 748 options.outputResourceEdges = args.output_resource_edges 749 if args.output_group_edges: 750 options.outputGroupEdges = args.output_group_edges 751 if args.analyze_service_account_impersonation: 752 options.analyzeServiceAccountImpersonation = args.analyze_service_account_impersonation 753 754 operation = None 755 if api_version == V1P4BETA1_API_VERSION: 756 request = self.message_module.ExportIamPolicyAnalysisRequest( 757 analysisQuery=analysis_query, 758 options=options, 759 outputConfig=output_config) 760 request_message = self.message_module.CloudassetExportIamPolicyAnalysisRequest( 761 parent=scope, exportIamPolicyAnalysisRequest=request) 762 operation = self.service.ExportIamPolicyAnalysis(request_message) 763 else: 764 analysis_query.options = options 765 request = self.message_module.AnalyzeIamPolicyLongrunningRequest( 766 analysisQuery=analysis_query, outputConfig=output_config) 767 request_message = self.message_module.CloudassetAnalyzeIamPolicyLongrunningRequest( 768 scope=scope, analyzeIamPolicyLongrunningRequest=request) 769 operation = self.service.AnalyzeIamPolicyLongrunning(request_message) 770 771 return operation 772 773 774class AnalyzeMoveClient(object): 775 """Client for analyzing resource move.""" 776 777 def __init__(self, api_version=DEFAULT_API_VERSION): 778 self.api_version = api_version 779 self.message_module = GetMessages(api_version) 780 self.service = GetClient(api_version).v1 781 782 def AnalyzeMove(self, args): 783 """Analyze resource move.""" 784 project = 'projects/' + args.project 785 786 if args.IsSpecified('destination_folder'): 787 destination = 'folders/' + args.destination_folder 788 else: 789 destination = 'organizations/' + args.destination_organization 790 791 scope = self.message_module.CloudassetAnalyzeMoveRequest.ViewValueValuesEnum.FULL 792 if args.blockers_only: 793 scope = self.message_module.CloudassetAnalyzeMoveRequest.ViewValueValuesEnum.BASIC 794 795 request_message = self.message_module.CloudassetAnalyzeMoveRequest( 796 destinationParent=destination, resource=project, view=scope) 797 798 return self.service.AnalyzeMove(request_message) 799