369 lines
13 KiB
Python
369 lines
13 KiB
Python
# -*- 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')
|