File: //snap/google-cloud-cli/current/lib/googlecloudsdk/api_lib/cloudresourcemanager/projects_api.py
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Useful commands for interacting with the Cloud Resource Management API."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.cloudresourcemanager import projects_util
from googlecloudsdk.api_lib.resource_manager import folders
from googlecloudsdk.command_lib.iam import iam_util
DEFAULT_API_VERSION = projects_util.DEFAULT_API_VERSION
def List(limit=None,
filter=None, # pylint: disable=redefined-builtin
batch_size=500,
api_version=DEFAULT_API_VERSION):
"""Make API calls to List active projects.
Args:
limit: The number of projects to limit the results to. This limit is passed
to the server and the server does the limiting.
filter: The client side filter expression.
batch_size: the number of projects to get with each request.
api_version: the version of the api
Returns:
Generator that yields projects
"""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
return list_pager.YieldFromList(
client.projects,
messages.CloudresourcemanagerProjectsListRequest(
filter=_AddActiveProjectFilterIfNotSpecified(filter)),
batch_size=batch_size,
limit=limit,
field='projects',
batch_size_attribute='pageSize')
def Search(limit=None,
query=None,
batch_size=500,
api_version='v3'):
"""Make API calls to search projects for which the user has resourcemanager.projects.get permission.
Args:
limit: The number of projects to limit the results to. This limit is passed
to the server and the server does the limiting.
query: The server side filter expression.
batch_size: The number of projects to get with each request.
api_version: The version of the api.
Returns:
Generator that yields projects.
"""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
return list_pager.YieldFromList(
client.projects,
messages.CloudresourcemanagerProjectsSearchRequest(
query=query),
method='Search',
batch_size=batch_size,
limit=limit,
field='projects',
batch_size_attribute='pageSize')
def ListV3(limit=None,
batch_size=500,
parent=None):
"""Make API calls to List active projects.
Args:
limit: The number of projects to limit the results to. This limit is passed
to the server and the server does the limiting.
batch_size: the number of projects to get with each request.
parent: The parent folder or organization whose children are to be listed.
Returns:
Generator that yields projects
"""
client = projects_util.GetClient('v3')
messages = projects_util.GetMessages('v3')
return list_pager.YieldFromList(
client.projects,
messages.CloudresourcemanagerProjectsListRequest(
parent=parent),
batch_size=batch_size,
limit=limit,
field='projects',
batch_size_attribute='pageSize')
def _AddActiveProjectFilterIfNotSpecified(filter_expr):
if not filter_expr:
return 'lifecycleState:ACTIVE'
if 'lifecycleState' in filter_expr:
return filter_expr
return 'lifecycleState:ACTIVE AND ({})'.format(filter_expr)
def Get(project_ref, api_version=DEFAULT_API_VERSION,
disable_api_enablement_check=False):
"""Get project information."""
client = projects_util.GetClient(api_version)
# disable_api_enablement_check added to handle special case of
# setting config value core/project, see b/133841504/
if disable_api_enablement_check:
client.check_response_func = None
return client.projects.Get(
client.MESSAGES_MODULE.CloudresourcemanagerProjectsGetRequest(
projectId=project_ref.projectId))
def Create(project_ref,
display_name=None,
parent=None,
labels=None,
tags=None,
api_version=DEFAULT_API_VERSION):
"""Create a new project.
Args:
project_ref: The identifier for the project
display_name: Optional display name for the project
parent: Optional for the project (ex. folders/123 or organizations/5231)
labels: Optional labels to apply to the project
tags: Optional tags to bind to the project
api_version: the version of the api
Returns:
An Operation object which can be used to check on the progress of the
project creation.
"""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
return client.projects.Create(
messages.Project(
projectId=project_ref.Name(),
name=display_name if display_name else project_ref.Name(),
parent=parent,
labels=labels,
tags=tags))
def Delete(project_ref, api_version=DEFAULT_API_VERSION):
"""Delete an existing project."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
client.projects.Delete(
messages.CloudresourcemanagerProjectsDeleteRequest(
projectId=project_ref.Name()))
return projects_util.DeletedResource(project_ref.Name())
def Undelete(project_ref, api_version=DEFAULT_API_VERSION):
"""Undelete a project that has been deleted."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
client.projects.Undelete(
messages.CloudresourcemanagerProjectsUndeleteRequest(
projectId=project_ref.Name()))
return projects_util.DeletedResource(project_ref.Name())
def Update(project_ref,
name=None,
parent=None,
labels_diff=None,
api_version=DEFAULT_API_VERSION):
"""Update project information."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
project = client.projects.Get(
client.MESSAGES_MODULE.CloudresourcemanagerProjectsGetRequest(
projectId=project_ref.projectId))
if name:
project.name = name
if parent:
project.parent = parent
if labels_diff:
labels_update = labels_diff.Apply(messages.Project.LabelsValue,
project.labels)
if labels_update.needs_update:
project.labels = labels_update.labels
return client.projects.Update(project)
def GetIamPolicy(project_ref, api_version=DEFAULT_API_VERSION):
"""Get IAM policy for a given project."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
policy_request = messages.CloudresourcemanagerProjectsGetIamPolicyRequest(
getIamPolicyRequest=messages.GetIamPolicyRequest(
options=messages.GetPolicyOptions(
requestedPolicyVersion=
iam_util.MAX_LIBRARY_IAM_SUPPORTED_VERSION)),
resource=project_ref.Name(),
)
return client.projects.GetIamPolicy(policy_request)
def GetAncestry(project_id, api_version=DEFAULT_API_VERSION):
"""Get ancestry for a given project."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
ancestry_request = messages.CloudresourcemanagerProjectsGetAncestryRequest(
getAncestryRequest=messages.GetAncestryRequest(),
projectId=project_id,
)
return client.projects.GetAncestry(ancestry_request)
def SetIamPolicy(project_ref,
policy,
update_mask=None,
api_version=DEFAULT_API_VERSION):
"""Set IAM policy, for a given project."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
policy.version = iam_util.MAX_LIBRARY_IAM_SUPPORTED_VERSION
set_iam_policy_request = messages.SetIamPolicyRequest(policy=policy)
# Only include update_mask if provided, otherwise, leave the field unset.
if update_mask is not None:
set_iam_policy_request.updateMask = update_mask
policy_request = messages.CloudresourcemanagerProjectsSetIamPolicyRequest(
resource=project_ref.Name(),
setIamPolicyRequest=set_iam_policy_request)
return client.projects.SetIamPolicy(policy_request)
def SetIamPolicyFromFile(project_ref,
policy_file,
api_version=DEFAULT_API_VERSION):
"""Read projects IAM policy from a file, and set it."""
messages = projects_util.GetMessages(api_version)
policy, update_mask = iam_util.ParsePolicyFileWithUpdateMask(
policy_file, messages.Policy)
# To preserve the existing set-iam-policy behavior of always overwriting
# bindings and etag, add bindings and etag to update_mask.
if 'bindings' not in update_mask:
update_mask += ',bindings'
if 'etag' not in update_mask:
update_mask += ',etag'
return SetIamPolicy(project_ref, policy, update_mask, api_version)
def AddIamPolicyBinding(project_ref,
member,
role,
api_version=DEFAULT_API_VERSION):
return AddIamPolicyBindings(project_ref, [(member, role)], api_version)
def AddIamPolicyBindings(project_ref,
member_roles,
api_version=DEFAULT_API_VERSION):
"""Adds iam bindings to project_ref's iam policy.
Args:
project_ref: The project for the binding
member_roles: List of 2-tuples of the form [(member, role), ...].
api_version: The version of the api
Returns:
The updated IAM Policy
"""
messages = projects_util.GetMessages(api_version)
policy = GetIamPolicy(project_ref, api_version)
for member, role in member_roles:
iam_util.AddBindingToIamPolicy(messages.Binding, policy, member, role)
return SetIamPolicy(project_ref, policy, api_version=api_version)
def AddIamPolicyBindingWithCondition(project_ref,
member,
role,
condition,
api_version=DEFAULT_API_VERSION):
"""Add iam binding with condition to project_ref's iam policy."""
messages = projects_util.GetMessages(api_version)
policy = GetIamPolicy(project_ref, api_version=api_version)
iam_util.AddBindingToIamPolicyWithCondition(messages.Binding, messages.Expr,
policy, member, role, condition)
return SetIamPolicy(project_ref, policy, api_version=api_version)
def RemoveIamPolicyBinding(project_ref,
member,
role,
api_version=DEFAULT_API_VERSION):
policy = GetIamPolicy(project_ref, api_version=api_version)
iam_util.RemoveBindingFromIamPolicy(policy, member, role)
return SetIamPolicy(project_ref, policy, api_version=api_version)
def RemoveIamPolicyBindingWithCondition(project_ref,
member,
role,
condition,
all_conditions,
api_version=DEFAULT_API_VERSION):
"""Remove iam binding with condition from project_ref's iam policy."""
policy = GetIamPolicy(project_ref, api_version=api_version)
iam_util.RemoveBindingFromIamPolicyWithCondition(policy, member, role,
condition, all_conditions)
return SetIamPolicy(project_ref, policy, api_version=api_version)
def TestIamPermissions(project_ref,
permissions,
api_version=DEFAULT_API_VERSION):
"""Return a subset of the given permissions that a caller has on project_ref."""
client = projects_util.GetClient(api_version)
messages = projects_util.GetMessages(api_version)
request = messages.CloudresourcemanagerProjectsTestIamPermissionsRequest(
resource=project_ref.Name(),
testIamPermissionsRequest=messages.TestIamPermissionsRequest(
permissions=permissions))
return client.projects.TestIamPermissions(request)
def ParentNameToResourceId(parent_name, api_version=DEFAULT_API_VERSION):
messages = projects_util.GetMessages(api_version)
if not parent_name:
return None
elif parent_name.startswith('folders/'):
return messages.ResourceId(
id=folders.FolderNameToId(parent_name), type='folder')
elif parent_name.startswith('organizations/'):
return messages.ResourceId(
id=parent_name[len('organizations/'):], type='organization')