# -*- coding: utf-8 -*- # # Copyright 2018 Google LLC. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """The utils for asset surface.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import re from googlecloudsdk.calliope import exceptions as gcloud_exceptions from googlecloudsdk.command_lib.projects import util as project_util from googlecloudsdk.core import properties def SetDefaultScopeIfEmpty(unused_ref, args, request): """Update the request scope to fall back to core project if not specified. Used by Asset Search gcloud `modify_request_hooks`. When --scope flag is not specified, it will modify the request.scope to fallback to the core properties project. Args: unused_ref: unused. args: The argument namespace. request: The request to modify. Returns: The modified request. """ request.scope = GetDefaultScopeIfEmpty(args) return request def GetDefaultScopeIfEmpty(args): """Return the request scope and fall back to core project if not specified.""" if args.scope: VerifyScopeForSearch(args.scope) return args.scope else: return 'projects/{0}'.format(properties.VALUES.core.project.GetOrFail()) def VerifyScopeForSearch(scope): """Perform permissive validation of the search scope. This validation is required although the API server contains similar request validation. The reason is that a malformed scope will be translated into an invalid URL, resulting in 404. For example, scope "projects/123/abc/" is translated to "https://cloudasset.googleapis.com/v1p1beta1/projects/123/abc/resources:searchAll".(404) However our OnePlatform API only accepts URL in format: "https://cloudasset.googleapis.com/v1p1beta1/*/*/resources:searchAll" Args: scope: the scope string of a search request. """ if not re.match('^[^/#?]+/[^/#?]+$', scope): raise gcloud_exceptions.InvalidArgumentException( '--scope', 'A valid scope should be: projects/{PROJECT_ID}, ' 'projects/{PROJECT_NUMBER}, folders/{FOLDER_NUMBER} or ' 'organizations/{ORGANIZATION_NUMBER}.') def VerifyParentForExport(organization, project, folder, attribute='root cloud asset'): """Verify the parent name.""" if organization is None and project is None and folder is None: raise gcloud_exceptions.RequiredArgumentException( '--organization or --project or --folder', 'Should specify the organization, or project, or the folder for ' '{0}.'.format(attribute)) if organization and project: raise gcloud_exceptions.ConflictingArgumentsException( 'organization', 'project') if organization and folder: raise gcloud_exceptions.ConflictingArgumentsException( 'organization', 'folder') if project and folder: raise gcloud_exceptions.ConflictingArgumentsException('project', 'folder') def GetParentNameForExport(organization, project, folder, attribute='root cloud asset'): """Gets the parent name from organization Id, project Id, or folder Id.""" VerifyParentForExport(organization, project, folder, attribute) if organization: return 'organizations/{0}'.format(organization) if folder: return 'folders/{0}'.format(folder) return 'projects/{0}'.format(project) def GetFeedParent(organization, project, folder): """Get the parent name from organization Number, project Id, or folder Number.""" if organization: return 'organizations/{0}'.format(organization) if folder: return 'folders/{0}'.format(folder) return 'projects/{0}'.format(project_util.GetProjectNumber(project)) def GetSavedQueriesParent(organization, project, folder): """Get the parent name from organization Number, project Id, or folder Number.""" if organization: return 'organizations/{0}'.format(organization) if folder: return 'folders/{0}'.format(folder) return 'projects/{0}'.format(project_util.GetProjectNumber(project)) def VerifyParentForGetHistory(organization, project, attribute='root cloud asset'): """Verify the parent name.""" if organization is None and project is None: raise gcloud_exceptions.RequiredArgumentException( '--organization or --project', 'Should specify the organization, or project for {0}.'.format( attribute)) if organization and project: raise gcloud_exceptions.ConflictingArgumentsException( 'organization', 'project') def GetParentNameForGetHistory(organization, project, attribute='root cloud asset'): """Gets the parent name from organization Id, project Id.""" VerifyParentForGetHistory(organization, project, attribute) if organization: return 'organizations/{0}'.format(organization) return 'projects/{0}'.format(project) def GetParentNameForAnalyzeIamPolicy(organization, project, folder, attribute='policy analysis scope'): """Gets the parent name from organization Id, project Id, or folder Id.""" # Analyzer supports the same set of parents as ExportAssets. return GetParentNameForExport(organization, project, folder, attribute)