18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# -*- coding: utf-8 -*-
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright 2011 Google Inc. All Rights Reserved.
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Licensed under the Apache License, Version 2.0 (the "License");
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# you may not use this file except in compliance with the License.
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# You may obtain a copy of the License at
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#     http://www.apache.org/licenses/LICENSE-2.0
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Unless required by applicable law or agreed to in writing, software
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# distributed under the License is distributed on an "AS IS" BASIS,
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# See the License for the specific language governing permissions and
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# limitations under the License.
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""Implementation of acl command for cloud storage providers."""
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom __future__ import absolute_import
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib import aclhelpers
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.cloud_api import AccessDeniedException
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.cloud_api import BadRequestException
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.cloud_api import Preconditions
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.cloud_api import ServiceException
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.command import Command
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.command import SetAclExceptionHandler
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.command import SetAclFuncWrapper
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.command_argument import CommandArgument
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.cs_api_map import ApiSelector
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.exception import CommandException
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.help_provider import CreateHelpText
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.storage_url import StorageUrlFromString
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.third_party.storage_apitools import storage_v1_messages as apitools_messages
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.util import NO_MAX
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.util import Retry
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom gslib.util import UrlsAreForSingleProvider
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_SET_SYNOPSIS = """
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  gsutil acl set [-f] [-r] [-a] file-or-canned_acl_name url...
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_GET_SYNOPSIS = """
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  gsutil acl get url
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_CH_SYNOPSIS = """
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  gsutil acl ch [-f] [-r] -u|-g|-d|-p <grant>... url...
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  where each <grant> is one of the following forms:
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -u <id|email>:<perm>
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -g <id|email|domain|All|AllAuth>:<perm>
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -p <viewers|editors|owners>-<project number>
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -d <id|email|domain|All|AllAuth>
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_GET_DESCRIPTION = """
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>GET</B>
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The "acl get" command gets the ACL text for a bucket or object, which you can
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  save and edit for the acl set command.
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_SET_DESCRIPTION = """
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>SET</B>
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The "acl set" command allows you to set an Access Control List on one or
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  more buckets and objects. The simplest way to use it is to specify one of
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  the canned ACLs, e.g.,:
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl set private gs://bucket
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  If you want to make an object or bucket publicly readable or writable, it is
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  recommended to use "acl ch", to avoid accidentally removing OWNER permissions.
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  See "gsutil help acl ch" for details.
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  See "gsutil help acls" for a list of all canned ACLs.
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  If you want to define more fine-grained control over your data, you can
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  retrieve an ACL using the "acl get" command, save the output to a file, edit
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  the file, and then use the "acl set" command to set that ACL on the buckets
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  and/or objects. For example:
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl get gs://bucket/file.txt > acl.txt
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Make changes to acl.txt such as adding an additional grant, then:
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl set acl.txt gs://cats/file.txt
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Note that you can set an ACL on multiple buckets or objects at once,
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  for example:
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl set acl.txt gs://bucket/*.jpg
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  If you have a large number of ACLs to update you might want to use the
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  gsutil -m option, to perform a parallel (multi-threaded/multi-processing)
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  update:
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil -m acl set acl.txt gs://bucket/*.jpg
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Note that multi-threading/multi-processing is only done when the named URLs
99cef7893435aa41160dd1255c43cb8498279738ccChris Craik  refer to objects, which happens either if you name specific objects or
100cef7893435aa41160dd1255c43cb8498279738ccChris Craik  if you enumerate objects by using an object wildcard or specifying
101cef7893435aa41160dd1255c43cb8498279738ccChris Craik  the acl -r flag.
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>SET OPTIONS</B>
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The "set" sub-command has the following options
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -R, -r      Performs "acl set" request recursively, to all objects under
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                the specified URL.
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -a          Performs "acl set" request on all object versions.
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -f          Normally gsutil stops at the first error. The -f option causes
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                it to continue when it encounters errors. If some of the ACLs
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                couldn't be set, gsutil's exit status will be non-zero even if
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                this flag is set. This option is implicitly set when running
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "gsutil -m acl...".
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_CH_DESCRIPTION = """
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>CH</B>
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The "acl ch" (or "acl change") command updates access control lists, similar
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  in spirit to the Linux chmod command. You can specify multiple access grant
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  additions and deletions in a single command run; all changes will be made
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  atomically to each object in turn. For example, if the command requests
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  deleting one grant and adding a different grant, the ACLs being updated will
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  never be left in an intermediate state where one grant has been deleted but
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  the second grant not yet added. Each change specifies a user or group grant
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  to add or delete, and for grant additions, one of R, W, O (for the
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  permission to be granted). A more formal description is provided in a later
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  section; below we provide examples.
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>CH EXAMPLES</B>
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Examples for "ch" sub-command:
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant anyone on the internet READ access to the object example-object:
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -u AllUsers:R gs://example-bucket/example-object
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  NOTE: By default, publicly readable objects are served with a Cache-Control
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  header allowing such objects to be cached for 3600 seconds. If you need to
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  ensure that updates become visible immediately, you should set a
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Cache-Control header of "Cache-Control:private, max-age=0, no-transform" on
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  such objects. For help doing this, see "gsutil help setmeta".
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant anyone on the internet WRITE access to the bucket example-bucket
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  (WARNING: this is not recommended as you will be responsible for the content):
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -u AllUsers:W gs://example-bucket
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant the user john.doe@example.com WRITE access to the bucket
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  example-bucket:
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -u john.doe@example.com:WRITE gs://example-bucket
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant the group admins@example.com OWNER access to all jpg files in
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  the top level of example-bucket:
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -g admins@example.com:O gs://example-bucket/*.jpg
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant the owners of project example-project-123 WRITE access to the bucket
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  example-bucket:
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -p owners-example-project-123:W gs://example-bucket
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  NOTE: You can replace 'owners' with 'viewers' or 'editors' to grant access
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  to a project's viewers/editors respectively.
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant the user with the specified canonical ID READ access to all objects
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  in example-bucket that begin with folder/:
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -r \\
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      -u 84fac329bceSAMPLE777d5d22b8SAMPLE785ac2SAMPLE2dfcf7c4adf34da46:R \\
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gs://example-bucket/folder/
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant the service account foo@developer.gserviceaccount.com WRITE access to
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  the bucket example-bucket:
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -u foo@developer.gserviceaccount.com:W gs://example-bucket
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant all users from the `Google Apps
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  <https://www.google.com/work/apps/business/>`_ domain my-domain.org READ
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  access to the bucket gcs.my-domain.org:
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -g my-domain.org:R gs://gcs.my-domain.org
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Remove any current access by john.doe@example.com from the bucket
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  example-bucket:
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil acl ch -d john.doe@example.com gs://example-bucket
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  If you have a large number of objects to update, enabling multi-threading
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  with the gsutil -m flag can significantly improve performance. The
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  following command adds OWNER for admin@example.org using
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  multi-threading:
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil -m acl ch -r -u admin@example.org:O gs://example-bucket
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Grant READ access to everyone from my-domain.org and to all authenticated
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  users, and grant OWNER to admin@mydomain.org, for the buckets
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  my-bucket and my-other-bucket, with multi-threading enabled:
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gsutil -m acl ch -r -g my-domain.org:R -g AllAuth:R \\
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      -u admin@mydomain.org:O gs://my-bucket/ gs://my-other-bucket
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>CH ROLES</B>
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  You may specify the following roles with either their shorthand or
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  their full name:
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    R: READ
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    W: WRITE
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    O: OWNER
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>CH ENTITIES</B>
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  There are four different entity types: Users, Groups, All Authenticated Users,
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  and All Users.
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Users are added with -u and a plain ID or email address, as in
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  "-u john-doe@gmail.com:r". Note: Service Accounts are considered to be users.
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Groups are like users, but specified with the -g flag, as in
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  "-g power-users@example.com:fc". Groups may also be specified as a full
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  domain, as in "-g my-company.com:r".
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  AllAuthenticatedUsers and AllUsers are specified directly, as
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  in "-g AllUsers:R" or "-g AllAuthenticatedUsers:O". These are case
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  insensitive, and may be shortened to "all" and "allauth", respectively.
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Removing roles is specified with the -d flag and an ID, email
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  address, domain, or one of AllUsers or AllAuthenticatedUsers.
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  Many entities' roles can be specified on the same command line, allowing
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  bundled changes to be executed in a single run. This will reduce the number of
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  requests made to the server.
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi<B>CH OPTIONS</B>
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The "ch" sub-command has the following options
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -d          Remove all roles associated with the matching entity.
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -f          Normally gsutil stops at the first error. The -f option causes
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                it to continue when it encounters errors. With this option the
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                gsutil exit status will be 0 even if some ACLs couldn't be
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                changed.
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -g          Add or modify a group entity's role.
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -p          Add or modify a project viewers/editors/owners role.
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -R, -r      Performs acl ch request recursively, to all objects under the
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                specified URL.
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    -u          Add or modify a user entity's role.
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_SYNOPSIS = (_SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') +
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi             _CH_SYNOPSIS.lstrip('\n') + '\n\n')
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_DESCRIPTION = ("""
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  The acl command has three sub-commands:
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi""" + '\n'.join([_GET_DESCRIPTION, _SET_DESCRIPTION, _CH_DESCRIPTION]))
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION)
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION)
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION)
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi_ch_help_text = CreateHelpText(_CH_SYNOPSIS, _CH_DESCRIPTION)
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef _ApplyExceptionHandler(cls, exception):
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  cls.logger.error('Encountered a problem: %s', exception)
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  cls.everything_set_okay = False
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef _ApplyAclChangesWrapper(cls, url_or_expansion_result, thread_state=None):
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  cls.ApplyAclChanges(url_or_expansion_result, thread_state=thread_state)
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass AclCommand(Command):
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  """Implementation of gsutil acl command."""
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  # Command specification. See base class for documentation.
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  command_spec = Command.CreateCommandSpec(
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      'acl',
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      command_name_aliases=['getacl', 'setacl', 'chacl'],
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      usage_synopsis=_SYNOPSIS,
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      min_args=2,
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      max_args=NO_MAX,
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      supported_sub_args='afRrg:u:d:p:',
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      file_url_ok=False,
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      provider_url_ok=False,
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      urls_start_arg=1,
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gs_api_support=[ApiSelector.XML, ApiSelector.JSON],
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gs_default_api=ApiSelector.JSON,
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      argparse_arguments={
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'set': [
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              CommandArgument.MakeFileURLOrCannedACLArgument(),
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              CommandArgument.MakeZeroOrMoreCloudURLsArgument()
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          ],
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'get': [
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              CommandArgument.MakeNCloudURLsArgument(1)
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          ],
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'ch': [
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              CommandArgument.MakeZeroOrMoreCloudURLsArgument()
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          ],
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  )
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  # Help specification. See help_provider.py for documentation.
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  help_spec = Command.HelpSpec(
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      help_name='acl',
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      help_name_aliases=['getacl', 'setacl', 'chmod', 'chacl'],
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      help_type='command_help',
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      help_one_line_summary='Get, set, or change bucket and/or object ACLs',
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      help_text=_DETAILED_HELP_TEXT,
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      subcommand_help_text={
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'get': _get_help_text, 'set': _set_help_text, 'ch': _ch_help_text},
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  )
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def _CalculateUrlsStartArg(self):
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if not self.args:
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self.RaiseWrongNumberOfArgumentsException()
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (self.args[0].lower() == 'set') or (self.command_alias_used == 'setacl'):
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      return 1
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    else:
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      return 0
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def _SetAcl(self):
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """Parses options and sets ACLs on the specified buckets/objects."""
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.continue_on_error = False
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if self.sub_opts:
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      for o, unused_a in self.sub_opts:
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if o == '-a':
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.all_versions = True
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-f':
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.continue_on_error = True
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-r' or o == '-R':
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.recursion_requested = True
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.RaiseInvalidArgumentException()
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    try:
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self.SetAclCommandHelper(SetAclFuncWrapper, SetAclExceptionHandler)
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    except AccessDeniedException, unused_e:
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self._WarnServiceAccounts()
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if not self.everything_set_okay:
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException('ACLs for some objects could not be set.')
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def _ChAcl(self):
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """Parses options and changes ACLs on the specified buckets/objects."""
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.parse_versions = True
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.changes = []
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.continue_on_error = False
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if self.sub_opts:
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      for o, a in self.sub_opts:
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if o == '-f':
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.continue_on_error = True
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-g':
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          if 'gserviceaccount.com' in a:
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise CommandException(
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'Service accounts are considered users, not groups; please use '
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '"gsutil acl ch -u" instead of "gsutil acl ch -g"')
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.changes.append(
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.GROUP))
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-p':
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.changes.append(
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.PROJECT))
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-u':
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.changes.append(
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.USER))
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-d':
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.changes.append(aclhelpers.AclDel(a))
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif o == '-r' or o == '-R':
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.recursion_requested = True
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          self.RaiseInvalidArgumentException()
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if not self.changes:
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException(
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'Please specify at least one access change '
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'with the -g, -u, or -d flags')
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (not UrlsAreForSingleProvider(self.args) or
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        StorageUrlFromString(self.args[0]).scheme != 'gs'):
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException(
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          'The "{0}" command can only be used with gs:// URLs'.format(
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              self.command_name))
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.everything_set_okay = True
3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.ApplyAclFunc(_ApplyAclChangesWrapper, _ApplyExceptionHandler,
3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                      self.args)
3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if not self.everything_set_okay:
3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException('ACLs for some objects could not be set.')
3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def _RaiseForAccessDenied(self, url):
3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self._WarnServiceAccounts()
3968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    raise CommandException('Failed to set acl for %s. Please ensure you have '
3978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                           'OWNER-role access to this resource.' % url)
3988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  @Retry(ServiceException, tries=3, timeout_secs=1)
4008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def ApplyAclChanges(self, name_expansion_result, thread_state=None):
4018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """Applies the changes in self.changes to the provided URL.
4028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    Args:
4048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      name_expansion_result: NameExpansionResult describing the target object.
4058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      thread_state: If present, gsutil Cloud API instance to apply the changes.
4068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
4078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if thread_state:
4088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gsutil_api = thread_state
4098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    else:
4108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gsutil_api = self.gsutil_api
4118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    url = name_expansion_result.expanded_storage_url
4138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if url.IsBucket():
4158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      bucket = gsutil_api.GetBucket(url.bucket_name, provider=url.scheme,
4168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                    fields=['acl', 'metageneration'])
4178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      current_acl = bucket.acl
4188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    elif url.IsObject():
4198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      gcs_object = gsutil_api.GetObjectMetadata(
4208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          url.bucket_name, url.object_name, provider=url.scheme,
4218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          generation=url.generation,
4228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          fields=['acl', 'generation', 'metageneration'])
4238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      current_acl = gcs_object.acl
4248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if not current_acl:
4258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self._RaiseForAccessDenied(url)
4268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    modification_count = 0
4288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    for change in self.changes:
4298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      modification_count += change.Execute(url, current_acl, 'acl', self.logger)
4308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if modification_count == 0:
4318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self.logger.info('No changes to %s', url)
4328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      return
4338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    try:
4358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if url.IsBucket():
4368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        preconditions = Preconditions(meta_gen_match=bucket.metageneration)
4378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        bucket_metadata = apitools_messages.Bucket(acl=current_acl)
4388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        gsutil_api.PatchBucket(url.bucket_name, bucket_metadata,
4398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               preconditions=preconditions,
4408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               provider=url.scheme, fields=['id'])
4418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      else:  # Object
4428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        preconditions = Preconditions(gen_match=gcs_object.generation,
4438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                      meta_gen_match=gcs_object.metageneration)
4448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        object_metadata = apitools_messages.Object(acl=current_acl)
4468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        gsutil_api.PatchObjectMetadata(
4478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            url.bucket_name, url.object_name, object_metadata,
4488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            preconditions=preconditions, provider=url.scheme,
4498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            generation=url.generation)
4508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    except BadRequestException as e:
4518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      # Don't retry on bad requests, e.g. invalid email address.
4528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException('Received bad request from server: %s' % str(e))
4538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    except AccessDeniedException:
4548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self._RaiseForAccessDenied(url)
4558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.logger.info('Updated ACL on %s', url)
4578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  def RunCommand(self):
4598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """Command entry point for the acl command."""
4608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    action_subcommand = self.args.pop(0)
4618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.ParseSubOpts(check_args=True)
4628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    self.def_acl = False
4638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if action_subcommand == 'get':
4648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self.GetAndPrintAcl(self.args[0])
4658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    elif action_subcommand == 'set':
4668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self._SetAcl()
4678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    elif action_subcommand in ('ch', 'change'):
4688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      self._ChAcl()
4698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    else:
4708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      raise CommandException(('Invalid subcommand "%s" for the %s command.\n'
4718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                              'See "gsutil help acl".') %
4728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                             (action_subcommand, self.command_name))
4738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return 0
475