class AddIamPolicyBinding(base.Command):
    """Add an IAM policy binding to a Google Compute Engine image.

  *{command}* adds an IAM policy binding to a Google Compute Engine
  image's access policy.
  """
    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'image', 'my-image', role='roles/compute.securityAdmin', use_an=True)

    @staticmethod
    def Args(parser):
        AddIamPolicyBinding.disk_image_arg = images_flags.MakeDiskImageArg(
            plural=False)
        AddIamPolicyBinding.disk_image_arg.AddArgument(
            parser, operation_type='add the IAM policy binding to')
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        client = holder.client
        image_ref = AddIamPolicyBinding.disk_image_arg.ResolveAsResource(
            args, holder.resources)
        get_request = client.messages.ComputeImagesGetIamPolicyRequest(
            resource=image_ref.image, project=image_ref.project)
        policy = client.apitools_client.images.GetIamPolicy(get_request)
        iam_util.AddBindingToIamPolicy(client.messages.Binding, policy,
                                       args.member, args.role)
        # TODO(b/78371568): Construct the GlobalSetPolicyRequest directly
        # out of the parsed policy.
        set_request = client.messages.ComputeImagesSetIamPolicyRequest(
            globalSetPolicyRequest=client.messages.GlobalSetPolicyRequest(
                bindings=policy.bindings, etag=policy.etag),
            resource=image_ref.image,
            project=image_ref.project)
        return client.apitools_client.images.SetIamPolicy(set_request)
Пример #2
0
class AddIamPolicyBinding(base.Command):
    """Add an IAM policy binding to a Google Compute Engine disk.

  *{command}* adds an IAM policy binding to a Google Compute Engine
  disk's access policy.
  """
    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'disk', 'my-disk', role='roles/compute.securityAdmin')

    @staticmethod
    def Args(parser):
        AddIamPolicyBinding.disk_arg = disks_flags.MakeDiskArg(plural=False)
        AddIamPolicyBinding.disk_arg.AddArgument(
            parser, operation_type='add the IAM policy binding to')
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        client = holder.client
        disk_ref = AddIamPolicyBinding.disk_arg.ResolveAsResource(
            args, holder.resources)
        get_request = client.messages.ComputeDisksGetIamPolicyRequest(
            resource=disk_ref.disk,
            zone=disk_ref.zone,
            project=disk_ref.project)
        policy = client.apitools_client.disks.GetIamPolicy(get_request)
        iam_util.AddBindingToIamPolicy(client.messages.Binding, policy,
                                       args.member, args.role)
        set_request = client.messages.ComputeDisksSetIamPolicyRequest(
            zoneSetPolicyRequest=client.messages.ZoneSetPolicyRequest(
                policy=policy),
            resource=disk_ref.disk,
            zone=disk_ref.zone,
            project=disk_ref.project)
        return client.apitools_client.disks.SetIamPolicy(set_request)
Пример #3
0
class AddIamPolicyBinding(base.Command):
    """Adds IAM policy binding to a service's access policy."""

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'service', 'my-service')

    @staticmethod
    def Args(parser):
        """Args is called by calliope to gather arguments for this command.

    Args:
      parser: An argparse parser that you can use to add arguments that go
          on the command line after this command. Positional arguments are
          allowed.
    """
        service_flag = common_flags.service_flag(
            suffix='to which the member is to be added')
        service_flag.AddToParser(parser)

        iam_util.AddArgsForAddIamPolicyBinding(parser)

    @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
    def Run(self, args):
        """Run 'service-management add-iam-policy-binding'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the access API call.

    Raises:
      ToolException: An error such as specifying a label that doesn't exist
        or a principal that is already a member of the service or visibility
        label.
    """
        messages = services_util.GetMessagesModule()
        client = services_util.GetClientInstance()
        request = messages.ServicemanagementServicesGetIamPolicyRequest(
            servicesId=args.service)

        try:
            policy = client.services.GetIamPolicy(request)
        except apitools_exceptions.HttpError as error:
            # If the error is a 404, no IAM policy exists, so just create a blank one.
            exc = exceptions.HttpException(error)
            if exc.payload.status_code == 404:
                policy = messages.Policy()
            else:
                raise

        iam_util.AddBindingToIamPolicy(messages, policy, args.member,
                                       args.role)

        # Send updated access policy to backend
        request = messages.ServicemanagementServicesSetIamPolicyRequest(
            servicesId=args.service,
            setIamPolicyRequest=(messages.SetIamPolicyRequest(policy=policy)))
        return client.services.SetIamPolicy(request)
Пример #4
0
class AddIamPolicyBinding(base_classes.BaseIamCommand):
  """Add an IAM policy binding to a service account.

  This command adds a policy binding to the IAM policy of a service account,
  given an IAM_ACCOUNT and the binding.
  """

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'service account',
      '*****@*****.**')
  detailed_help['DESCRIPTION'] += '\n\n' + (
      iam_util.GetHintForServiceAccountResource('add iam policy bindings to'))

  @staticmethod
  def Args(parser):
    iam_util.AddServiceAccountNameArg(
        parser,
        action='whose policy to add bindings to')
    iam_util.AddArgsForAddIamPolicyBinding(parser)

  @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
  def Run(self, args):
    policy = self.iam_client.projects_serviceAccounts.GetIamPolicy(
        self.messages.IamProjectsServiceAccountsGetIamPolicyRequest(
            resource=iam_util.EmailToAccountResourceName(args.service_account)))

    iam_util.AddBindingToIamPolicy(self.messages.Binding, policy, args.member,
                                   args.role)

    return self.iam_client.projects_serviceAccounts.SetIamPolicy(
        self.messages.IamProjectsServiceAccountsSetIamPolicyRequest(
            resource=iam_util.EmailToAccountResourceName(args.service_account),
            setIamPolicyRequest=self.messages.SetIamPolicyRequest(
                policy=policy)))
class AddIamPolicyBindingAlpha(base.Command):
  """Adds IAM policy binding to a model.

  Adds a policy binding to the IAM policy of a ML engine model, given a model ID
  and the binding. One binding consists of a member, a role, and an optional
  condition.
  """
  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'model', 'my_model', role='roles/ml.admin', condition=True)

  @staticmethod
  def Args(parser):
    flags.GetModelName().AddToParser(parser)
    iam_util.AddArgsForAddIamPolicyBinding(
        parser,
        flags.MlEngineIamRolesCompleter,
        add_condition=True)

  def Run(self, args):
    condition = iam_util.ValidateAndExtractCondition(args)
    iam_util.ValidateMutexConditionAndPrimitiveRoles(condition, args.role)
    return models_util.AddIamPolicyBindingWithCondition(
        models.ModelsClient(),
        args.model,
        args.member,
        args.role,
        condition)
class AddIamPolicyBinding(base.Command):
    """Add an IAM policy binding to a queue's access policy."""

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'queue', 'my-queue', role='roles/cloudtasks.queueAdmin')

    @staticmethod
    def Args(parser):
        flags.AddQueueResourceArg(parser, 'to add the IAM policy binding to')
        flags.AddLocationFlag(parser)
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    def Run(self, args):
        queues_client = queues.Queues()
        queues_messages = queues_client.api.messages
        queue_ref = parsers.ParseQueue(args.queue, args.location)
        try:
            policy = queues_client.GetIamPolicy(queue_ref)
        except apitools_exceptions.HttpNotFoundError:
            # If the error is a 404, no IAM policy exists, so just create a blank one.
            policy = queues_messages.Policy()
        iam_util.AddBindingToIamPolicy(queues_messages.Binding, policy,
                                       args.member, args.role)
        response = queues_client.SetIamPolicy(queue_ref, policy)
        return response
Пример #7
0
class AddIamPolicyBinding(base.Command):
    """Add IAM policy binding for a project.

  Adds a policy binding to the IAM policy of a project,
  given a project ID and the binding.
  """

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'project', 'example-project-id-1')

    def Collection(self):
        return command_lib_util.PROJECTS_COLLECTION

    def GetUriFunc(self):
        return command_lib_util.ProjectsUriFunc

    @staticmethod
    def Args(parser):
        flags.GetProjectFlag('add IAM policy binding to').AddToParser(parser)
        iam_util.AddArgsForAddIamPolicyBinding(
            parser, 'id', 'cloudresourcemanager.projects')

    @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
    def Run(self, args):
        project_ref = command_lib_util.ParseProject(args.id)
        return projects_api.AddIamPolicyBinding(project_ref, args.member,
                                                args.role)
Пример #8
0
class AddIamPolicyBinding(orgs_base.OrganizationCommand):
  """Add IAM policy binding for an organization.

  Adds a policy binding to the IAM policy of an organization,
  given an organization ID and the binding.
  """

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding('organization',
                                                                 '123456789')

  @staticmethod
  def Args(parser):
    flags.IdArg('to which you want to add a binding').AddToParser(parser)
    iam_util.AddArgsForAddIamPolicyBinding(
        parser, completer=completers.OrganizationsIamRolesCompleter)

  @http_retry.RetryOnHttpStatus(six.moves.http_client.CONFLICT)
  def Run(self, args):
    messages = self.OrganizationsMessages()

    get_policy_request = (
        messages.CloudresourcemanagerOrganizationsGetIamPolicyRequest(
            organizationsId=args.id,
            getIamPolicyRequest=messages.GetIamPolicyRequest()))
    policy = self.OrganizationsClient().GetIamPolicy(get_policy_request)

    iam_util.AddBindingToIamPolicy(
        messages.Binding, policy, args.member, args.role)

    set_policy_request = (
        messages.CloudresourcemanagerOrganizationsSetIamPolicyRequest(
            organizationsId=args.id,
            setIamPolicyRequest=messages.SetIamPolicyRequest(policy=policy)))

    return self.OrganizationsClient().SetIamPolicy(set_policy_request)
class AddIamPolicyBinding(base.Command):
  """Add IAM policy binding for a folder.

  Adds a policy binding to the IAM policy of a folder,
  given a folder ID and the binding.
  """

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'folder', '3589215982')

  @staticmethod
  def Args(parser):
    flags.FolderIdArg('to which you want to add a binding').AddToParser(parser)
    iam_util.AddArgsForAddIamPolicyBinding(
        parser,
        role_completer=completers.FoldersIamRolesCompleter)

  # Allow for retries due to ETag-based optimistic concurrency control
  @http_retry.RetryOnHttpStatus(six.moves.http_client.CONFLICT)
  def Run(self, args):
    messages = folders.FoldersMessages()
    policy = folders.GetIamPolicy(args.id)
    iam_util.AddBindingToIamPolicy(
        messages.Binding, policy, args.member, args.role)
    return folders.SetIamPolicy(args.id, policy)
Пример #10
0
class AddIamPolicyBinding(base_classes.BaseIamCommand):
    """Add an IAM policy binding to a service account.

  This command adds a policy binding to the IAM policy of a service account,
  given an IAM-ACCOUNT and the binding.
  """

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'service account', '*****@*****.**')

    @staticmethod
    def Args(parser):
        parser.add_argument('account',
                            metavar='IAM-ACCOUNT',
                            help='The service account whose policy to '
                            'add bindings to.')
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
    def Run(self, args):
        policy = self.iam_client.projects_serviceAccounts.GetIamPolicy(
            self.messages.IamProjectsServiceAccountsGetIamPolicyRequest(
                resource=iam_util.EmailToAccountResourceName(args.account)))

        iam_util.AddBindingToIamPolicy(self.messages, policy, args.member,
                                       args.role)

        return self.iam_client.projects_serviceAccounts.SetIamPolicy(
            self.messages.IamProjectsServiceAccountsSetIamPolicyRequest(
                resource=iam_util.EmailToAccountResourceName(args.account),
                setIamPolicyRequest=self.messages.SetIamPolicyRequest(
                    policy=policy)))
Пример #11
0
class AddIamPolicyBindingBeta(AddIamPolicyBinding):
    """Add IAM policy binding to a model."""

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'model', 'my_model', role='roles/ml.admin', condition=False)

    @staticmethod
    def Args(parser):
        _AddIamPolicyBindingFlags(parser)

    def Run(self, args):
        return _Run(args)
class SetIamPolicy(base_classes.BaseIamCommand):
    """Add an IAM policy binding to a Cloud Pub/Sub Topic."""

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'topic', 'my-topic')

    @staticmethod
    def Args(parser):
        flags.AddTopicResourceArg(parser, 'to add an IAM policy binding to.')
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    def Run(self, args):
        client = topics.TopicsClient()
        topic_ref = util.ParseTopic(args.topic)
        return client.AddIamPolicyBinding(topic_ref, args.member, args.role)
Пример #13
0
class AddIamPolicyBinding(base_classes.BaseIamCommand):
  """Add an IAM policy binding to a Cloud Pub/Sub Subscription."""

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'subscription', 'my-subscription')

  @staticmethod
  def Args(parser):
    flags.AddSubscriptionResourceArg(parser,
                                     'to add an IAM policy binding to.')
    iam_util.AddArgsForAddIamPolicyBinding(parser)

  def Run(self, args):
    client = subscriptions.SubscriptionsClient()
    subscription_ref = util.ParseSubscription(args.subscription)
    return client.AddIamPolicyBinding(subscription_ref, args.member, args.role)
class AddIamPolicyBinding(base.Command):
    """Add an IAM policy binding to a Google Compute Engine instance.

  *{command}* adds an IAM policy binding to a Google Compute Engine
  instance's access policy.
  """
    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'instance',
        'my-instance',
        role='roles/compute.securityAdmin',
        use_an=True)

    @staticmethod
    def Args(parser):
        flags.INSTANCE_ARG.AddArgument(
            parser, operation_type='add the IAM policy binding to')
        iam_util.AddArgsForAddIamPolicyBinding(parser)

    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        client = holder.client

        instance_ref = flags.INSTANCE_ARG.ResolveAsResource(
            args,
            holder.resources,
            scope_lister=flags.GetInstanceZoneScopeLister(client))

        policy = client.MakeRequests([
            (client.apitools_client.instances, 'GetIamPolicy',
             client.messages.ComputeInstancesGetIamPolicyRequest(
                 resource=instance_ref.instance,
                 zone=instance_ref.zone,
                 project=instance_ref.project))
        ])[0]
        iam_util.AddBindingToIamPolicy(client.messages.Binding, policy,
                                       args.member, args.role)
        # TODO(b/78371568): Construct the ZoneSetPolicyRequest directly
        # out of the parsed policy.
        return client.MakeRequests([
            (client.apitools_client.instances, 'SetIamPolicy',
             client.messages.ComputeInstancesSetIamPolicyRequest(
                 zoneSetPolicyRequest=client.messages.ZoneSetPolicyRequest(
                     bindings=policy.bindings, etag=policy.etag),
                 project=instance_ref.project,
                 resource=instance_ref.instance,
                 zone=instance_ref.zone))
        ])[0]
Пример #15
0
class AddIamPolicyBinding(base.Command):
  """Add IAM policy binding for a project.

  Adds a policy binding to the IAM policy of a project,
  given a project ID and the binding.
  """

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'project', 'example-project-id-1')

  @staticmethod
  def Args(parser):
    flags.GetProjectFlag('add IAM policy binding to').AddToParser(parser)
    iam_util.AddArgsForAddIamPolicyBinding(
        parser, completer=completers.ProjectsIamRolesCompleter)

  @http_retry.RetryOnHttpStatus(six.moves.http_client.CONFLICT)
  def Run(self, args):
    project_ref = command_lib_util.ParseProject(args.id)
    return projects_api.AddIamPolicyBinding(project_ref, args.member, args.role)
Пример #16
0
class AddIamPolicyBindingAlpha(orgs_base.OrganizationCommand):
  """Add IAM policy binding for an organization.

  Adds a policy binding to the IAM policy of an organization,
  given an organization ID and the binding. One binding consists of a member, a
  role, and an optional condition.
  """

  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'organization', 'example-organization-id-1', use_an=True, condition=True)

  @staticmethod
  def Args(parser):
    flags.IdArg('to which you want to add a binding').AddToParser(parser)
    iam_util.AddArgsForAddIamPolicyBinding(
        parser,
        role_completer=completers.OrganizationsIamRolesCompleter,
        add_condition=True)

  @http_retry.RetryOnHttpStatus(six.moves.http_client.CONFLICT)
  def Run(self, args):
    condition = iam_util.ValidateAndExtractConditionMutexRole(args)

    messages = self.OrganizationsMessages()
    get_policy_request = (
        messages.CloudresourcemanagerOrganizationsGetIamPolicyRequest(
            organizationsId=args.id,
            getIamPolicyRequest=messages.GetIamPolicyRequest()))

    policy = self.OrganizationsClient().GetIamPolicy(get_policy_request)

    iam_util.AddBindingToIamPolicyWithCondition(messages.Binding, messages.Expr,
                                                policy, args.member, args.role,
                                                condition)

    set_policy_request = (
        messages.CloudresourcemanagerOrganizationsSetIamPolicyRequest(
            organizationsId=args.id,
            setIamPolicyRequest=messages.SetIamPolicyRequest(policy=policy)))

    return self.OrganizationsClient().SetIamPolicy(set_policy_request)
Пример #17
0
class AddIamPolicyBinding(base.Command):
    """Add IAM policy binding for a dataset.

  This command adds a policy binding to the IAM policy of a dataset,
  given a dataset ID and the binding.
  """

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'dataset', '1000')

    @staticmethod
    def Args(parser):
        parser.add_argument('id', type=str, help='The ID of the dataset.')
        iam_util.AddArgsForAddIamPolicyBinding(parser, 'id',
                                               'genomics.datasets')

    @genomics_util.ReraiseHttpException
    def Run(self, args):
        apitools_client = genomics_util.GetGenomicsClient()
        messages = genomics_util.GetGenomicsMessages()

        dataset_resource = resources.REGISTRY.Parse(
            args.id, collection='genomics.datasets')

        policy_request = messages.GenomicsDatasetsGetIamPolicyRequest(
            resource='datasets/{0}'.format(dataset_resource.Name()),
            getIamPolicyRequest=messages.GetIamPolicyRequest(),
        )
        policy = apitools_client.datasets.GetIamPolicy(policy_request)

        iam_util.AddBindingToIamPolicy(messages, policy, args.member,
                                       args.role)

        policy_request = messages.GenomicsDatasetsSetIamPolicyRequest(
            resource='datasets/{0}'.format(dataset_resource.Name()),
            setIamPolicyRequest=messages.SetIamPolicyRequest(policy=policy),
        )
        return apitools_client.datasets.SetIamPolicy(policy_request)
Пример #18
0
class AddIamPolicyBindingAlpha(base.Command):
    """Adds IAM policy binding to a model.

  Adds a policy binding to the IAM policy of a ML engine model, given a model ID
  and the binding. One binding consists of a member, a role, and an optional
  condition.
  """
    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'model', 'my_model', role='roles/ml.admin', condition=True)

    @staticmethod
    def Args(parser):
        _AddIamPolicyBindingFlags(parser,
                                  add_condition=True,
                                  hide_region_flag=False)

    def Run(self, args):
        with endpoint_util.MlEndpointOverrides(region=args.region):
            condition = iam_util.ValidateAndExtractCondition(args)
            iam_util.ValidateMutexConditionAndPrimitiveRoles(
                condition, args.role)
            return models_util.AddIamPolicyBindingWithCondition(
                models.ModelsClient(), args.model, args.member, args.role,
                condition)
Пример #19
0
class AddIamPolicyBindingAlpha(base.Command):
    """Add IAM policy binding for a project.

  Adds a policy binding to the IAM policy of a project, given a project ID and
  the binding. One binding consists of a member, a role, and an optional
  condition.
  """
    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'project', 'example-project-id-1', condition=True)

    @staticmethod
    def Args(parser):
        flags.GetProjectFlag('add IAM policy binding to').AddToParser(parser)
        iam_util.AddArgsForAddIamPolicyBinding(
            parser,
            role_completer=completers.ProjectsIamRolesCompleter,
            add_condition=True)

    @http_retry.RetryOnHttpStatus(six.moves.http_client.CONFLICT)
    def Run(self, args):
        project_ref = command_lib_util.ParseProject(args.id)
        condition = iam_util.ValidateAndExtractConditionMutexRole(args)
        return projects_api.AddIamPolicyBindingWithCondition(
            project_ref, args.member, args.role, condition)
class AddIamPolicyBinding(base.Command):
  """Adds IAM policy binding to a service's access policy."""

  # This detailed help helper interacts weirdly with the deprecate decorator...
  # Messages are doubled and I'm not sure why. Still, not harmful.
  detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
      'service', 'my-service', role='roles/servicemanagement.serviceConsumer')

  @staticmethod
  def Args(parser):
    """Args is called by calliope to gather arguments for this command.

    Args:
      parser: An argparse parser that you can use to add arguments that go
          on the command line after this command. Positional arguments are
          allowed.
    """
    service_flag = common_flags.producer_service_flag(
        suffix='to which the member is to be added')
    service_flag.AddToParser(parser)

    iam_util.AddArgsForAddIamPolicyBinding(parser)

  @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
  def Run(self, args):
    """Run 'service-management add-iam-policy-binding'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the access API call.

    Raises:
      ToolException: An error such as specifying a label that doesn't exist
        or a principal that is already a member of the service or visibility
        label.
    """
    messages = services_util.GetMessagesModule()
    client = services_util.GetClientInstance()

    service = arg_parsers.GetServiceNameFromArg(args.service)

    request = messages.ServicemanagementServicesGetIamPolicyRequest(
        servicesId=service)

    try:
      policy = client.services.GetIamPolicy(request)
    except apitools_exceptions.HttpNotFoundError:
      # If the error is a 404, no IAM policy exists, so just create a blank one.
      policy = messages.Policy()

    iam_util.AddBindingToIamPolicy(
        messages.Binding, policy, args.member, args.role)

    # Send updated access policy to backend
    request = messages.ServicemanagementServicesSetIamPolicyRequest(
        servicesId=service,
        setIamPolicyRequest=(messages.SetIamPolicyRequest(policy=policy)))
    return client.services.SetIamPolicy(request)
Пример #21
0
class AddIamPolicyBinding(base.Command,
                          base_classes.BaseServiceManagementCommand):
    """Adds IAM policy binding to a service's access policy."""

    detailed_help = iam_util.GetDetailedHelpForAddIamPolicyBinding(
        'service', 'my-service')

    @staticmethod
    def Args(parser):
        """Args is called by calliope to gather arguments for this command.

    Args:
      parser: An argparse parser that you can use to add arguments that go
          on the command line after this command. Positional arguments are
          allowed.
    """
        service_flag = common_flags.service_flag(
            suffix='to which the member is to be added')
        service_flag.AddToParser(parser)

        parser.add_argument('--member',
                            required=True,
                            help='The member to add to the binding.')

    @http_error_handler.HandleHttpErrors
    @http_retry.RetryOnHttpStatus(httplib.CONFLICT)
    def Run(self, args):
        """Run 'service-management add-iam-policy-binding'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the access API call.

    Raises:
      ToolException: An error such as specifying a label that doesn't exist
        or a principal that is already a member of the service or visibility
        label.
    """
        request = (self.services_messages.
                   ServicemanagementServicesGetIamPolicyRequest(
                       servicesId=args.service))

        try:
            policy = self.services_client.services.GetIamPolicy(request)
        except apitools_exceptions.HttpError as error:
            # If the error is a 404, no IAM policy exists, so just create a blank one.
            if http_error_handler.GetHttpErrorStatusCode(error) == 404:
                policy = self.services_messages.Policy()
            else:
                raise

        iam_util.AddBindingToIamPolicy(
            self.services_messages, policy, args.member,
            'roles/servicemanagement.serviceConsumer')

        # Send updated access policy to backend
        request = (self.services_messages.
                   ServicemanagementServicesSetIamPolicyRequest(
                       servicesId=args.service,
                       setIamPolicyRequest=(
                           self.services_messages.SetIamPolicyRequest(
                               policy=policy))))
        return self.services_client.services.SetIamPolicy(request)