feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.

View File

@@ -0,0 +1,563 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""Declarative hooks for Cloud Identity Groups CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import collections
from apitools.base.py import encoding
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.identity import cloudidentity_client as ci_client
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.organizations import org_utils
import six
GROUP_TYPE_MAP = {
'discussion': ['cloudidentity.googleapis.com/groups.discussion_forum'],
'dynamic': ['cloudidentity.googleapis.com/groups.dynamic'],
'security': ['cloudidentity.googleapis.com/groups.discussion_forum',
'cloudidentity.googleapis.com/groups.security'],
}
# request hooks
def SetParent(unused_ref, args, request):
"""Set obfuscated customer id to request.group.parent or request.parent.
Args:
unused_ref: A string representing the operation reference. Unused and may be
None.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
group = getattr(request, 'group', None)
if group is None:
request.group = messages.Group()
request.group.parent = GetCustomerId(args)
return request
def SetEntityKey(unused_ref, args, request):
"""Set EntityKey to request.group.groupKey.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if hasattr(args, 'email'):
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
request.group.groupKey = messages.EntityKey(id=args.email)
return request
def SetLabels(unused_ref, args, request):
"""Set Labels to request.group.labels.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('labels'):
if hasattr(request.group, 'labels'):
request.group.labels = ReformatLabels(args, args.labels)
else:
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
request.group = messages.Group(labels=ReformatLabels(args, args.labels))
return request
def SetLabelsCreate(unused_ref, args, request):
"""Set Labels to request.group.labels for the create command.
Labels will be used from args.labels if supplied, otherwise labels
will be looked up based on the args.group_type argument. If neither is
supplied, labels will be set based on the 'discussion' group type.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('labels'):
labels = args.labels
elif args.IsKnownAndSpecified('group_type'):
labels = ','.join(GROUP_TYPE_MAP[args.group_type])
else:
labels = ','.join(GROUP_TYPE_MAP['discussion'])
if hasattr(request.group, 'labels'):
request.group.labels = ReformatLabels(args, labels)
else:
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
request.group = messages.Group(labels=ReformatLabels(args, labels))
return request
def SetInitialOwner(unused_ref, args, request):
"""Set the initial owner.
Defaults to 'empty' for dynamic groups and to 'with-initial-owner' for
other group types.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('with_initial_owner'):
return request
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
create_message = messages.CloudidentityGroupsCreateRequest
config_enum = create_message.InitialGroupConfigValueValuesEnum
if ((args.IsSpecified('group_type') and 'dynamic' in args.group_type)
or (args.IsSpecified('labels') and 'dynamic' in args.labels)):
request.initialGroupConfig = config_enum.EMPTY
else:
request.initialGroupConfig = config_enum.WITH_INITIAL_OWNER
return request
def SetResourceName(unused_ref, args, request):
"""Set resource name to request.name.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('email'):
version = GetApiVersion(args)
request.name = ConvertEmailToResourceName(version, args.email, '--email')
return request
def SetPageSize(unused_ref, args, request):
"""Set page size to request.pageSize.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('page_size'):
request.pageSize = int(args.page_size)
return request
def SetGroupUpdateMask(unused_ref, args, request):
"""Set the update mask on the request based on the args.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
Raises:
InvalidArgumentException: If no fields are specified to update.
"""
update_mask = []
if (args.IsSpecified('display_name') or
args.IsSpecified('clear_display_name')):
update_mask.append('display_name')
if (args.IsSpecified('description') or args.IsSpecified('clear_description')):
update_mask.append('description')
if hasattr(args, 'labels'):
if args.IsSpecified('labels'):
update_mask.append('labels')
if hasattr(args, 'add_posix_group'):
if (args.IsSpecified('add_posix_group') or
args.IsSpecified('remove_posix_groups') or
args.IsSpecified('clear_posix_groups')):
update_mask.append('posix_groups')
if args.IsSpecified('dynamic_user_query'):
update_mask.append('dynamic_group_metadata')
if not update_mask:
raise exceptions.InvalidArgumentException(
'Must specify at least one field mask.')
request.updateMask = ','.join(update_mask)
return request
def GenerateQuery(unused_ref, args, request):
"""Generate and set the query on the request based on the args.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
customer_id = GetCustomerId(args)
labels = FilterLabels(args.labels)
labels_str = ','.join(labels)
request.query = 'parent==\"{0}\" && \"{1}\" in labels'.format(
customer_id, labels_str)
return request
def UpdateDisplayName(unused_ref, args, request):
"""Update displayName.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('clear_display_name'):
request.group.displayName = ''
elif args.IsSpecified('display_name'):
request.group.displayName = args.display_name
return request
def UpdateDescription(unused_ref, args, request):
"""Update description.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if args.IsSpecified('clear_description'):
request.group.description = ''
elif args.IsSpecified('description'):
request.group.description = args.description
return request
def UpdatePosixGroups(unused_ref, args, request):
"""Update posix groups.
When adding posix groups, the posix groups in the request will be combined
with the current posix groups. When removing groups, the current list of
posix groups is retrieved and if any value in args.remove_posix_groups
matches either a name or gid in a current posix group, it will be removed
from the list and the remaining posix groups will be added to the update
request.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = GetApiVersion(args)
group = ci_client.GetGroup(version, request.name)
if args.IsSpecified('add_posix_group'):
request.group.posixGroups = request.group.posixGroups + group.posixGroups
elif args.IsSpecified('remove_posix_groups'):
if request.group is None:
request.group = group
for pg in list(group.posixGroups):
if (six.text_type(pg.gid) in args.remove_posix_groups or
pg.name in args.remove_posix_groups):
group.posixGroups.remove(pg)
request.group.posixGroups = group.posixGroups
return request
# processor hooks
def SetDynamicUserQuery(unused_ref, args, request):
"""Add DynamicGroupUserQuery to DynamicGroupQueries object list.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated dynamic group queries.
"""
queries = []
if args.IsSpecified('dynamic_user_query'):
dg_user_query = args.dynamic_user_query
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
resource_type = messages.DynamicGroupQuery.ResourceTypeValueValuesEnum
new_dynamic_group_query = messages.DynamicGroupQuery(
resourceType=resource_type.USER, query=dg_user_query)
queries.append(new_dynamic_group_query)
dynamic_group_metadata = messages.DynamicGroupMetadata(queries=queries)
if hasattr(request.group, 'dynamicGroupMetadata'):
request.group.dynamicGroupMetadata = dynamic_group_metadata
else:
request.group = messages.Group(
dynamicGroupMetadata=dynamic_group_metadata)
return request
def ReformatLabels(args, labels):
"""Reformat label list to encoded labels message.
Reformatting labels will be done within following two steps,
1. Filter label strings in a label list.
2. Convert the filtered label list to OrderedDict.
3. Encode the OrderedDict format of labels to group.labels message.
Args:
args: The argparse namespace.
labels: list of label strings. e.g.
["cloudidentity.googleapis.com/security=",
"cloudidentity.googleapis.com/groups.discussion_forum"]
Returns:
Encoded labels message.
Raises:
InvalidArgumentException: If invalid labels string is input.
"""
# Filter label strings in a label list.
filtered_labels = FilterLabels(labels)
# Convert the filtered label list to OrderedDict.
labels_dict = collections.OrderedDict()
for label in filtered_labels:
if '=' in label:
split_label = label.split('=')
labels_dict[split_label[0]] = split_label[1]
else:
labels_dict[label] = ''
# Encode the OrderedDict format of labels to group.labels message.
version = GetApiVersion(args)
messages = ci_client.GetMessages(version)
return encoding.DictToMessage(labels_dict, messages.Group.LabelsValue)
# private methods
def ConvertOrgArgToObfuscatedCustomerId(org_arg):
"""Convert organization argument to obfuscated customer id.
Args:
org_arg: organization argument
Returns:
Obfuscated customer id
Example:
org_id: 12345
organization_obj:
{
owner: {
directoryCustomerId: A08w1n5gg
}
}
"""
organization_obj = org_utils.GetOrganization(org_arg)
if organization_obj:
return organization_obj.owner.directoryCustomerId
else:
raise org_utils.UnknownOrganizationError(org_arg, metavar='ORGANIZATION')
def ConvertEmailToResourceName(version, email, arg_name):
"""Convert email to resource name.
Args:
version: Release track information
email: group email
arg_name: argument/parameter name
Returns:
Group Id (e.g. groups/11zu0gzc3tkdgn2)
"""
try:
return ci_client.LookupGroupName(version, email).name
except (apitools_exceptions.HttpForbiddenError,
apitools_exceptions.HttpNotFoundError):
# If there is no group exists (or deleted) for the given group email,
# print out an error message.
error_msg = ('There is no such a group associated with the specified '
'argument:' + email)
raise exceptions.InvalidArgumentException(arg_name, error_msg)
def FilterLabels(labels):
"""Filter label strings in label list.
Filter labels (list of strings) with the following conditions,
1. If 'label' has 'key' and 'value' OR 'key' only, then add the label to
filtered label list. (e.g. 'label_key=label_value', 'label_key')
2. If 'label' has an equal sign but no 'value', then add the 'key' to filtered
label list. (e.g. 'label_key=' ==> 'label_key')
3. If 'label' has invalid format of string, throw an InvalidArgumentException.
(e.g. 'label_key=value1=value2')
Args:
labels: list of label strings.
Returns:
Filtered label list.
Raises:
InvalidArgumentException: If invalid labels string is input.
"""
if not labels:
raise exceptions.InvalidArgumentException(
'labels', 'labels can not be an empty string')
# Convert a comma separated string to a list of strings.
label_list = labels.split(',')
filtered_labels = []
for label in label_list:
if '=' in label:
split_label = label.split('=')
# Catch invalid format like 'key=value1=value2'
if len(split_label) > 2:
raise exceptions.InvalidArgumentException(
'labels',
'Invalid format of label string has been input. Label: ' + label)
if split_label[1]:
filtered_labels.append(label) # Valid format #1: 'key=value'
else:
filtered_labels.append(split_label[0]) # Valid format #2: 'key'
else:
filtered_labels.append(label)
return filtered_labels
def GetApiVersion(args):
"""Return release track information.
Args:
args: The argparse namespace.
Returns:
Release track.
Raises:
UnsupportedReleaseTrackError: If invalid release track is input.
"""
release_track = args.calliope_command.ReleaseTrack()
if release_track == base.ReleaseTrack.ALPHA:
return 'v1alpha1'
elif release_track == base.ReleaseTrack.BETA:
return 'v1beta1'
elif release_track == base.ReleaseTrack.GA:
return 'v1'
else:
raise UnsupportedReleaseTrackError(release_track)
def GetCustomerId(args):
"""Return customer_id.
Args:
args: The argparse namespace.
Returns:
customer_id.
"""
if hasattr(args, 'customer') and args.IsSpecified('customer'):
customer_id = args.customer
elif hasattr(args, 'organization') and args.IsSpecified('organization'):
customer_id = ConvertOrgArgToObfuscatedCustomerId(args.organization)
return 'customerId/' + customer_id
class UnsupportedReleaseTrackError(Exception):
"""Raised when requesting an api for an unsupported release track."""

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.

View File

@@ -0,0 +1,572 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""Declarative hooks for Cloud Identity Groups Memberships CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.identity import cloudidentity_client as ci_client
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.identity.groups import hooks as groups_hooks
from googlecloudsdk.core.util import times
# request hooks
def SetMembership(unused_ref, args, request):
"""Set Membership in request.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
messages = ci_client.GetMessages(version)
request.membership = messages.Membership()
return request
def SetEntityKey(unused_ref, args, request):
"""Set EntityKey in group resource.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
messages = ci_client.GetMessages(version)
if hasattr(args, 'member_email') and args.IsSpecified('member_email'):
entity_key = messages.EntityKey(id=args.member_email)
request.membership.preferredMemberKey = entity_key
return request
def SetPageSize(unused_ref, args, request):
"""Set page size to request.pageSize.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if hasattr(args, 'page_size') and args.IsSpecified('page_size'):
request.pageSize = int(args.page_size)
return request
def SetMembershipParent(unused_ref, args, request):
"""Set resource name to request.parent.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
if args.IsSpecified('group_email'):
# Resource name example: groups/03qco8b4452k99t
request.parent = groups_hooks.ConvertEmailToResourceName(
version, args.group_email, '--group-email')
return request
def SetTransitiveMembershipParent(unused_ref, args, request):
"""Set resource name to request.parent.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
if hasattr(args, 'group_email') and args.IsSpecified('group_email'):
# Resource name example: groups/03qco8b4452k99t
request.parent = groups_hooks.ConvertEmailToResourceName(
version, args.group_email, '--group-email')
else:
# If this hook is used and no group_emails provided then set the parent to
# be the groups wildcard.
request.parent = 'groups/-'
return request
def SetMembershipResourceName(unused_ref, args, request):
"""Set membership resource name to request.name.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
name = ''
if args.IsSpecified('group_email') and args.IsSpecified('member_email'):
name = ConvertEmailToMembershipResourceName(
version, args, '--group-email', '--member-email')
else:
raise exceptions.InvalidArgumentException(
'Must specify `--group-email` and `--member-email` argument.')
request.name = name
if hasattr(request, 'membership'):
request.membership.name = name
return request
def SetMembershipRoles(unused_ref, args, request):
"""Set MembershipRoles to request.membership.roles.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
if not hasattr(args, 'roles') or not args.IsSpecified('roles'):
empty_list = []
request.membership.roles = ReformatMembershipRoles(version, empty_list)
else:
request.membership.roles = ReformatMembershipRoles(version, args.roles)
return request
def SetExpiryDetail(unused_ref, args, request):
"""Set expiration to request.membership.expiryDetail (v1alpha1) or in request.membership.roles (v1beta1).
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
Raises:
InvalidArgumentException: If 'expiration' is specified upon following cases:
1. 'request.membership' doesn't have 'roles' attribute, or
2. multiple roles are provided.
"""
### Pre-validations ###
# #1. In order to set Expiry Detail, there should be a role in
# 'request.membership'
if not hasattr(request.membership, 'roles'):
raise exceptions.InvalidArgumentException(
'expiration', 'roles must be specified.')
# #2. When setting 'expiration', a single role should be input.
if len(request.membership.roles) != 1:
raise exceptions.InvalidArgumentException(
'roles',
'When setting "expiration", a single role should be input.')
version = groups_hooks.GetApiVersion(args)
if hasattr(args, 'expiration') and args.IsSpecified('expiration'):
if version == 'v1alpha1':
request.membership.expiryDetail = ReformatExpiryDetail(
version, args.expiration, 'add')
else:
request.membership.roles = AddExpiryDetailInMembershipRoles(
version, request, args.expiration)
return request
def SetTransitiveQuery(unused_ref, args, request):
"""Sets query paremeters to request.query.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
params = []
if hasattr(args, 'member_email') and args.IsSpecified('member_email'):
params.append("member_key_id=='{}'".format(args.member_email))
if hasattr(args, 'labels') and args.IsSpecified('labels'):
params.append("'{}' in labels".format(args.labels))
request.query = '&&'.join(params)
return request
def UpdateMembershipRoles(unused_ref, args, request):
"""Update MembershipRoles to request.membership.roles.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
version = groups_hooks.GetApiVersion(args)
if hasattr(args, 'roles') and args.IsSpecified('roles'):
request.membership.roles = ReformatMembershipRoles(version, args.roles)
return request
def UpdateRoles(unused_ref, args, request):
"""Update 'MembershipRoles' to request.modifyMembershipRolesRequest.
Args:
unused_ref: unused.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
# Following logic is used only when 'add-roles' parameter is used.
if hasattr(args, 'add_roles') and args.IsSpecified('add_roles'):
# Convert a comma separated string to a list of strings.
role_list = args.add_roles.split(',')
# Convert a list of strings to a list of MembershipRole objects.
version = groups_hooks.GetApiVersion(args)
roles = []
messages = ci_client.GetMessages(version)
for role in role_list:
membership_role = messages.MembershipRole(name=role)
roles.append(membership_role)
request.modifyMembershipRolesRequest = messages.ModifyMembershipRolesRequest(
addRoles=roles)
return request
def SetUpdateRolesParams(unused_ref, args, request):
"""Update 'MembershipRoles' to request.modifyMembershipRolesRequest.
Args:
unused_ref: A string representing the operation reference. Unused and may
be None.
args: The argparse namespace.
request: The request to modify.
Returns:
The updated request.
"""
if hasattr(args,
'update_roles_params') and args.IsSpecified('update_roles_params'):
version = groups_hooks.GetApiVersion(args)
messages = ci_client.GetMessages(version)
request.modifyMembershipRolesRequest = messages.ModifyMembershipRolesRequest(
updateRolesParams=ReformatUpdateRolesParams(
args, args.update_roles_params))
return request
# private methods
def ConvertEmailToMembershipResourceName(
version, args, group_arg_name, member_arg_name):
"""Convert email to membership resource name.
Args:
version: Release track information
args: The argparse namespace
group_arg_name: argument/parameter name related to group info
member_arg_name: argument/parameter name related to member info
Returns:
Membership Id (e.g. groups/11zu0gzc3tkdgn2/memberships/1044279104595057141)
"""
# Resource name example: groups/03qco8b4452k99t
group_id = groups_hooks.ConvertEmailToResourceName(
version, args.group_email, group_arg_name)
try:
return ci_client.LookupMembershipName(
version, group_id, args.member_email).name
except (apitools_exceptions.HttpForbiddenError,
apitools_exceptions.HttpNotFoundError):
# If there is no group exists (or deleted) for the given group email,
# print out an error message.
parameter_name = group_arg_name + ', ' + member_arg_name
error_msg = ('There is no such membership associated with the specified '
'arguments: {}, {}').format(args.group_email,
args.member_email)
raise exceptions.InvalidArgumentException(parameter_name, error_msg)
def ReformatExpiryDetail(version, expiration, command):
"""Reformat expiration string to ExpiryDetail object.
Args:
version: Release track information
expiration: expiration string.
command: gcloud command name.
Returns:
ExpiryDetail object that contains the expiration data.
"""
messages = ci_client.GetMessages(version)
duration = 'P' + expiration
expiration_ts = FormatDateTime(duration)
if version == 'v1alpha1' and command == 'modify-membership-roles':
return messages.MembershipRoleExpiryDetail(expireTime=expiration_ts)
return messages.ExpiryDetail(expireTime=expiration_ts)
def ReformatMembershipRoles(version, roles_list):
"""Reformat roles string to MembershipRoles object list.
Args:
version: Release track information
roles_list: list of roles in a string format.
Returns:
List of MembershipRoles object.
"""
messages = ci_client.GetMessages(version)
roles = []
if not roles_list:
# If no MembershipRole is provided, 'MEMBER' is used as a default value.
roles.append(messages.MembershipRole(name='MEMBER'))
return roles
for role in roles_list:
new_membership_role = messages.MembershipRole(name=role)
roles.append(new_membership_role)
return roles
def GetUpdateMask(role_param, arg_name):
"""Set the update mask on the request based on the role param.
Args:
role_param: The param that needs to be updated for a specified role.
arg_name: The argument name
Returns:
Update mask
Raises:
InvalidArgumentException: If no fields are specified to update.
"""
update_mask = []
if role_param == 'expiration':
update_mask.append('expiry_detail.expire_time')
if not update_mask:
raise exceptions.InvalidArgumentException(
arg_name, 'Must specify at least one field mask.')
return ','.join(update_mask)
def FormatDateTime(duration):
"""Return RFC3339 string for datetime that is now + given duration.
Args:
duration: string ISO 8601 duration, e.g. 'P5D' for period 5 days.
Returns:
string timestamp
"""
# We use a format that preserves +00:00 for UTC to match timestamp format
# returned by container API.
fmt = '%Y-%m-%dT%H:%M:%S.%3f%Oz'
return times.FormatDateTime(
times.ParseDateTime(duration, tzinfo=times.UTC), fmt=fmt)
def AddExpiryDetailInMembershipRoles(version, request, expiration):
"""Add an expiration in request.membership.roles.
Args:
version: version
request: The request to modify
expiration: expiration date to set
Returns:
The updated roles.
Raises:
InvalidArgumentException: If 'expiration' is specified without MEMBER role.
"""
messages = ci_client.GetMessages(version)
roles = []
has_member_role = False
for role in request.membership.roles:
if hasattr(role, 'name') and role.name == 'MEMBER':
has_member_role = True
roles.append(messages.MembershipRole(
name='MEMBER',
expiryDetail=ReformatExpiryDetail(version, expiration, 'add')))
else:
roles.append(role)
# Checking whether the 'expiration' is specified with a MEMBER role.
if not has_member_role:
raise exceptions.InvalidArgumentException(
'expiration', 'Expiration date can be set with a MEMBER role only.')
return roles
def ReformatUpdateRolesParams(args, update_roles_params):
"""Reformat update_roles_params string.
Reformatting update_roles_params will be done by following steps,
1. Split the comma separated string to a list of strings.
2. Convert the splitted string to UpdateMembershipRolesParams message.
Args:
args: The argparse namespace.
update_roles_params: A comma separated string.
Returns:
A list of reformatted 'UpdateMembershipRolesParams'.
Raises:
InvalidArgumentException: If invalid update_roles_params string is input.
"""
# Split a comma separated 'update_roles_params' string.
update_roles_params_list = update_roles_params.split(',')
version = groups_hooks.GetApiVersion(args)
messages = ci_client.GetMessages(version)
roles_params = []
arg_name = '--update-roles-params'
for update_roles_param in update_roles_params_list:
role, param_key, param_value = TokenizeUpdateRolesParams(
update_roles_param, arg_name)
# Membership expiry is supported only on a MEMBER role.
if param_key == 'expiration' and role != 'MEMBER':
error_msg = ('Membership Expiry is not supported on a specified role: {}.'
).format(role)
raise exceptions.InvalidArgumentException(arg_name, error_msg)
# Instantiate MembershipRole object.
expiry_detail = ReformatExpiryDetail(
version, param_value, 'modify-membership-roles')
membership_role = messages.MembershipRole(
name=role, expiryDetail=expiry_detail)
update_mask = GetUpdateMask(param_key, arg_name)
update_membership_roles_params = messages.UpdateMembershipRolesParams(
fieldMask=update_mask, membershipRole=membership_role)
roles_params.append(update_membership_roles_params)
return roles_params
def TokenizeUpdateRolesParams(update_roles_param, arg_name):
"""Tokenize update_roles_params string.
Args:
update_roles_param: 'update_roles_param' string (e.g. MEMBER=expiration=3d)
arg_name: The argument name
Returns:
Tokenized strings: role (e.g. MEMBER), param_key (e.g. expiration), and
param_value (e.g. 3d)
Raises:
InvalidArgumentException: If invalid update_roles_param string is input.
"""
token_list = update_roles_param.split('=')
if len(token_list) == 3:
return token_list[0], token_list[1], token_list[2]
raise exceptions.InvalidArgumentException(
arg_name, 'Invalid format: ' + update_roles_param)

View File

@@ -0,0 +1,20 @@
group:
name: group
collection: cloudidentity.groups
request_id_field: groupsId
attributes:
- &group
parameter_name: groupId
attribute_name: group
help: group ID
membership:
name: membership
collection: cloudidentity.groups.memberships
request_id_field: membershipsId
attributes:
- *group
- &membership
parameter_name: membershipsId
attribute_name: membership
help: member ID