1 # -*- coding: utf-8 -*-
2 # Copyright 2011 Google Inc. All Rights Reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 """Implementation of default object acl command for Google Cloud Storage."""
17 from __future__
import absolute_import
19 from gslib
import aclhelpers
20 from gslib
.cloud_api
import AccessDeniedException
21 from gslib
.cloud_api
import BadRequestException
22 from gslib
.cloud_api
import Preconditions
23 from gslib
.cloud_api
import ServiceException
24 from gslib
.command
import Command
25 from gslib
.command
import SetAclExceptionHandler
26 from gslib
.command
import SetAclFuncWrapper
27 from gslib
.command_argument
import CommandArgument
28 from gslib
.cs_api_map
import ApiSelector
29 from gslib
.exception
import CommandException
30 from gslib
.help_provider
import CreateHelpText
31 from gslib
.storage_url
import StorageUrlFromString
32 from gslib
.third_party
.storage_apitools
import storage_v1_messages
as apitools_messages
33 from gslib
.util
import NO_MAX
34 from gslib
.util
import Retry
35 from gslib
.util
import UrlsAreForSingleProvider
38 gsutil defacl set file-or-canned_acl_name url...
46 gsutil defacl ch [-f] -u|-g|-d|-p <grant>... url...
49 _SET_DESCRIPTION
= """
51 The "defacl set" command sets default object ACLs for the specified buckets.
52 If you specify a default object ACL for a certain bucket, Google Cloud
53 Storage applies the default object ACL to all new objects uploaded to that
54 bucket, unless an ACL for that object is separately specified during upload.
56 Similar to the "acl set" command, the file-or-canned_acl_name names either a
57 canned ACL or the path to a file that contains ACL text. (See "gsutil
58 help acl" for examples of editing and setting ACLs via the
61 Setting a default object ACL on a bucket provides a convenient way to ensure
62 newly uploaded objects have a specific ACL. If you don't set the bucket's
63 default object ACL, it will default to project-private. If you then upload
64 objects that need a different ACL, you will need to perform a separate ACL
65 update operation for each object. Depending on how many objects require
66 updates, this could be very time-consuming.
69 _GET_DESCRIPTION
= """
71 Gets the default ACL text for a bucket, which you can save and edit
72 for use with the "defacl set" command.
77 The "defacl ch" (or "defacl change") command updates the default object
78 access control list for a bucket. The syntax is shared with the "acl ch"
79 command, so see the "CH" section of "gsutil help acl" for the full help
83 Grant anyone on the internet READ access by default to any object created
84 in the bucket example-bucket:
86 gsutil defacl ch -u AllUsers:R gs://example-bucket
88 NOTE: By default, publicly readable objects are served with a Cache-Control
89 header allowing such objects to be cached for 3600 seconds. If you need to
90 ensure that updates become visible immediately, you should set a
91 Cache-Control header of "Cache-Control:private, max-age=0, no-transform" on
92 such objects. For help doing this, see "gsutil help setmeta".
94 Add the user john.doe@example.com to the default object ACL on bucket
95 example-bucket with READ access:
97 gsutil defacl ch -u john.doe@example.com:READ gs://example-bucket
99 Add the group admins@example.com to the default object ACL on bucket
100 example-bucket with OWNER access:
102 gsutil defacl ch -g admins@example.com:O gs://example-bucket
104 Grant the owners of project example-project-123 READ access to new objects
105 created in the bucket example-bucket:
107 gsutil acl ch -p owners-example-project-123:R gs://example-bucket
109 NOTE: You can replace 'owners' with 'viewers' or 'editors' to grant access
110 to a project's viewers/editors respectively.
113 The "ch" sub-command has the following options
115 -d Remove all roles associated with the matching entity.
117 -f Normally gsutil stops at the first error. The -f option causes
118 it to continue when it encounters errors. With this option the
119 gsutil exit status will be 0 even if some ACLs couldn't be
122 -g Add or modify a group entity's role.
124 -p Add or modify a project viewers/editors/owners role.
126 -u Add or modify a user entity's role.
129 _SYNOPSIS
= (_SET_SYNOPSIS
+ _GET_SYNOPSIS
.lstrip('\n') +
130 _CH_SYNOPSIS
.lstrip('\n') + '\n\n')
133 The defacl command has three sub-commands:
134 """ + '\n'.join([_SET_DESCRIPTION
+ _GET_DESCRIPTION
+ _CH_DESCRIPTION
])
136 _DETAILED_HELP_TEXT
= CreateHelpText(_SYNOPSIS
, _DESCRIPTION
)
138 _get_help_text
= CreateHelpText(_GET_SYNOPSIS
, _GET_DESCRIPTION
)
139 _set_help_text
= CreateHelpText(_SET_SYNOPSIS
, _SET_DESCRIPTION
)
140 _ch_help_text
= CreateHelpText(_CH_SYNOPSIS
, _CH_DESCRIPTION
)
143 class DefAclCommand(Command
):
144 """Implementation of gsutil defacl command."""
146 # Command specification. See base class for documentation.
147 command_spec
= Command
.CreateCommandSpec(
149 command_name_aliases
=['setdefacl', 'getdefacl', 'chdefacl'],
150 usage_synopsis
=_SYNOPSIS
,
153 supported_sub_args
='fg:u:d:p:',
155 provider_url_ok
=False,
157 gs_api_support
=[ApiSelector
.XML
, ApiSelector
.JSON
],
158 gs_default_api
=ApiSelector
.JSON
,
161 CommandArgument
.MakeFileURLOrCannedACLArgument(),
162 CommandArgument
.MakeZeroOrMoreCloudBucketURLsArgument()
165 CommandArgument
.MakeNCloudBucketURLsArgument(1)
168 CommandArgument
.MakeZeroOrMoreCloudBucketURLsArgument()
172 # Help specification. See help_provider.py for documentation.
173 help_spec
= Command
.HelpSpec(
176 'default acl', 'setdefacl', 'getdefacl', 'chdefacl'],
177 help_type
='command_help',
178 help_one_line_summary
='Get, set, or change default ACL on buckets',
179 help_text
=_DETAILED_HELP_TEXT
,
180 subcommand_help_text
={
181 'get': _get_help_text
, 'set': _set_help_text
, 'ch': _ch_help_text
},
184 def _CalculateUrlsStartArg(self
):
186 self
.RaiseWrongNumberOfArgumentsException()
187 if (self
.args
[0].lower() == 'set' or
188 self
.command_alias_used
== 'setdefacl'):
193 def _SetDefAcl(self
):
194 if not StorageUrlFromString(self
.args
[-1]).IsBucket():
195 raise CommandException('URL must name a bucket for the %s command' %
198 self
.SetAclCommandHelper(SetAclFuncWrapper
, SetAclExceptionHandler
)
199 except AccessDeniedException
:
200 self
._WarnServiceAccounts
()
203 def _GetDefAcl(self
):
204 if not StorageUrlFromString(self
.args
[0]).IsBucket():
205 raise CommandException('URL must name a bucket for the %s command' %
207 self
.GetAndPrintAcl(self
.args
[0])
210 """Parses options and changes default object ACLs on specified buckets."""
211 self
.parse_versions
= True
215 for o
, a
in self
.sub_opts
:
218 aclhelpers
.AclChange(a
, scope_type
=aclhelpers
.ChangeType
.GROUP
))
221 aclhelpers
.AclChange(a
, scope_type
=aclhelpers
.ChangeType
.USER
))
224 aclhelpers
.AclChange(a
, scope_type
=aclhelpers
.ChangeType
.PROJECT
))
226 self
.changes
.append(aclhelpers
.AclDel(a
))
229 raise CommandException(
230 'Please specify at least one access change '
231 'with the -g, -u, or -d flags')
233 if (not UrlsAreForSingleProvider(self
.args
) or
234 StorageUrlFromString(self
.args
[0]).scheme
!= 'gs'):
235 raise CommandException(
236 'The "{0}" command can only be used with gs:// URLs'.format(
240 for url_arg
in self
.args
:
241 for result
in self
.WildcardIterator(url_arg
):
242 if not result
.storage_url
.IsBucket():
243 raise CommandException(
244 'The defacl ch command can only be applied to buckets.')
245 bucket_urls
.add(result
.storage_url
)
247 for storage_url
in bucket_urls
:
248 self
.ApplyAclChanges(storage_url
)
250 @Retry(ServiceException
, tries
=3, timeout_secs
=1)
251 def ApplyAclChanges(self
, url
):
252 """Applies the changes in self.changes to the provided URL."""
253 bucket
= self
.gsutil_api
.GetBucket(
254 url
.bucket_name
, provider
=url
.scheme
,
255 fields
=['defaultObjectAcl', 'metageneration'])
257 # Default object ACLs can be blank if the ACL was set to private, or
258 # if the user doesn't have permission. We warn about this with defacl get,
259 # so just try the modification here and if the user doesn't have
260 # permission they'll get an AccessDeniedException.
261 current_acl
= bucket
.defaultObjectAcl
263 modification_count
= 0
264 for change
in self
.changes
:
265 modification_count
+= change
.Execute(
266 url
, current_acl
, 'defacl', self
.logger
)
267 if modification_count
== 0:
268 self
.logger
.info('No changes to %s', url
)
272 preconditions
= Preconditions(meta_gen_match
=bucket
.metageneration
)
273 bucket_metadata
= apitools_messages
.Bucket(defaultObjectAcl
=current_acl
)
274 self
.gsutil_api
.PatchBucket(url
.bucket_name
, bucket_metadata
,
275 preconditions
=preconditions
,
276 provider
=url
.scheme
, fields
=['id'])
277 except BadRequestException
as e
:
278 # Don't retry on bad requests, e.g. invalid email address.
279 raise CommandException('Received bad request from server: %s' % str(e
))
280 except AccessDeniedException
:
281 self
._WarnServiceAccounts
()
282 raise CommandException('Failed to set acl for %s. Please ensure you have '
283 'OWNER-role access to this resource.' % url
)
285 self
.logger
.info('Updated default ACL on %s', url
)
287 def RunCommand(self
):
288 """Command entry point for the defacl command."""
289 action_subcommand
= self
.args
.pop(0)
290 self
.ParseSubOpts(check_args
=True)
292 self
.continue_on_error
= False
293 if action_subcommand
== 'get':
294 func
= self
._GetDefAcl
295 elif action_subcommand
== 'set':
296 func
= self
._SetDefAcl
297 elif action_subcommand
in ('ch', 'change'):
298 func
= self
._ChDefAcl
300 raise CommandException(('Invalid subcommand "%s" for the %s command.\n'
301 'See "gsutil help defacl".') %
302 (action_subcommand
, self
.command_name
))