Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: gslib/commands/defacl.py

Issue 698893003: Update checked in version of gsutil to version 4.6 (Closed) Base URL: http://dart.googlecode.com/svn/third_party/gsutil/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gslib/commands/cp.py ('k') | gslib/commands/du.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*-
1 # Copyright 2011 Google Inc. All Rights Reserved. 2 # Copyright 2011 Google Inc. All Rights Reserved.
2 # 3 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 5 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 6 # You may obtain a copy of the License at
6 # 7 #
7 # http://www.apache.org/licenses/LICENSE-2.0 8 # http://www.apache.org/licenses/LICENSE-2.0
8 # 9 #
9 # Unless required by applicable law or agreed to in writing, software 10 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and 13 # See the License for the specific language governing permissions and
13 # limitations under the License. 14 # limitations under the License.
15 """Implementation of default object acl command for Google Cloud Storage."""
16
17 from __future__ import absolute_import
14 18
15 import getopt 19 import getopt
16 20
17 from boto.exception import GSResponseError
18 from gslib import aclhelpers 21 from gslib import aclhelpers
22 from gslib.cloud_api import AccessDeniedException
23 from gslib.cloud_api import BadRequestException
24 from gslib.cloud_api import Preconditions
25 from gslib.cloud_api import ServiceException
19 from gslib.command import Command 26 from gslib.command import Command
20 from gslib.command import COMMAND_NAME 27 from gslib.command import SetAclExceptionHandler
21 from gslib.command import COMMAND_NAME_ALIASES 28 from gslib.command import SetAclFuncWrapper
22 from gslib.command import FILE_URIS_OK 29 from gslib.cs_api_map import ApiSelector
23 from gslib.command import MAX_ARGS
24 from gslib.command import MIN_ARGS
25 from gslib.command import PROVIDER_URIS_OK
26 from gslib.command import SUPPORTED_SUB_ARGS
27 from gslib.command import URIS_START_ARG
28 from gslib.exception import CommandException 30 from gslib.exception import CommandException
29 from gslib.help_provider import CreateHelpText 31 from gslib.help_provider import CreateHelpText
30 from gslib.help_provider import HELP_NAME 32 from gslib.storage_url import StorageUrlFromString
31 from gslib.help_provider import HELP_NAME_ALIASES 33 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m essages
32 from gslib.help_provider import HELP_ONE_LINE_SUMMARY
33 from gslib.help_provider import HELP_TEXT
34 from gslib.help_provider import HelpType
35 from gslib.help_provider import HELP_TYPE
36 from gslib.help_provider import SUBCOMMAND_HELP_TEXT
37 from gslib.util import NO_MAX 34 from gslib.util import NO_MAX
38 from gslib.util import Retry 35 from gslib.util import Retry
36 from gslib.util import UrlsAreForSingleProvider
39 37
40 _SET_SYNOPSIS = """ 38 _SET_SYNOPSIS = """
41 gsutil defacl set file-or-canned_acl_name uri... 39 gsutil defacl set file-or-canned_acl_name url...
42 """ 40 """
43 41
44 _GET_SYNOPSIS = """ 42 _GET_SYNOPSIS = """
45 gsutil defacl get uri 43 gsutil defacl get url
46 """ 44 """
47 45
48 _CH_SYNOPSIS = """ 46 _CH_SYNOPSIS = """
49 gsutil defacl ch -u|-g|-d <grant>... uri... 47 gsutil defacl ch -u|-g|-d <grant>... url...
50 """ 48 """
51 49
52 _SET_DESCRIPTION = """ 50 _SET_DESCRIPTION = """
53 <B>SET</B> 51 <B>SET</B>
54 The "defacl set" command sets default object ACLs for the specified buckets. 52 The "defacl set" command sets default object ACLs for the specified buckets.
55 If you specify a default object ACL for a certain bucket, Google Cloud 53 If you specify a default object ACL for a certain bucket, Google Cloud
56 Storage applies the default object ACL to all new objects uploaded to that 54 Storage applies the default object ACL to all new objects uploaded to that
57 bucket. 55 bucket.
58 56
59 Similar to the "acl set" command, the file-or-canned_acl_name names either a 57 Similar to the "acl set" command, the file-or-canned_acl_name names either a
60 canned ACL or the path to a file that contains ACL XML. (See "gsutil 58 canned ACL or the path to a file that contains ACL text. (See "gsutil
61 help acl" for examples of editing and setting ACLs via the 59 help acl" for examples of editing and setting ACLs via the
62 acl command.) 60 acl command.)
63 61
64 If you don't set a default object ACL on a bucket, the bucket's default 62 If you don't set a default object ACL on a bucket, the bucket's default
65 object ACL will be project-private. 63 object ACL will be project-private.
66 64
67 Setting a default object ACL on a bucket provides a convenient way 65 Setting a default object ACL on a bucket provides a convenient way
68 to ensure newly uploaded objects have a specific ACL, and avoids the 66 to ensure newly uploaded objects have a specific ACL, and avoids the
69 need to back after the fact and set ACLs on a large number of objects 67 need to back after the fact and set ACLs on a large number of objects
70 for which you forgot to set the ACL at object upload time (which can 68 for which you forgot to set the ACL at object upload time (which can
71 happen if you don't set a default object ACL on a bucket, and get the 69 happen if you don't set a default object ACL on a bucket, and get the
72 default project-private ACL). 70 default project-private ACL).
73 """ 71 """
74 72
75 _GET_DESCRIPTION = """ 73 _GET_DESCRIPTION = """
76 <B>GET</B> 74 <B>GET</B>
77 Gets the default ACL XML for a bucket, which you can save and edit 75 Gets the default ACL text for a bucket, which you can save and edit
78 for use with the "defacl set" command. 76 for use with the "defacl set" command.
79 """ 77 """
80 78
81 _CH_DESCRIPTION = """ 79 _CH_DESCRIPTION = """
82 <B>CH</B> 80 <B>CH</B>
83 The "defacl ch" (or "defacl change") command updates the default object 81 The "defacl ch" (or "defacl change") command updates the default object
84 access control list for a bucket. The syntax is shared with the "acl ch" 82 access control list for a bucket. The syntax is shared with the "acl ch"
85 command, so see the "CH" section of "gsutil help acl" for the full help 83 command, so see the "CH" section of "gsutil help acl" for the full help
86 description. 84 description.
87 85
88 <B>CH EXAMPLES</B> 86 <B>CH EXAMPLES</B>
89 Add the user john.doe@example.com to the default object ACL on bucket 87 Add the user john.doe@example.com to the default object ACL on bucket
90 example-bucket with READ access: 88 example-bucket with READ access:
91 89
92 gsutil defacl ch -u john.doe@example.com:READ gs://example-bucket 90 gsutil defacl ch -u john.doe@example.com:READ gs://example-bucket
93 91
94 Add the group admins@example.com to the default object ACL on bucket 92 Add the group admins@example.com to the default object ACL on bucket
95 example-bucket with FULL_CONTROL access: 93 example-bucket with OWNER access:
96 94
97 gsutil defacl ch -g admins@example.com:FC gs://example-bucket 95 gsutil defacl ch -g admins@example.com:O gs://example-bucket
98 """ 96 """
99 97
100 _SYNOPSIS = (_SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') + 98 _SYNOPSIS = (_SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') +
101 _CH_SYNOPSIS.lstrip('\n') + '\n\n') 99 _CH_SYNOPSIS.lstrip('\n') + '\n\n')
102 100
103 _DESCRIPTION = """ 101 _DESCRIPTION = """
104 The defacl command has three sub-commands: 102 The defacl command has three sub-commands:
105 """ + '\n'.join([_SET_DESCRIPTION + _GET_DESCRIPTION + _CH_DESCRIPTION]) 103 """ + '\n'.join([_SET_DESCRIPTION + _GET_DESCRIPTION + _CH_DESCRIPTION])
106 104
107 _detailed_help_text = CreateHelpText(_SYNOPSIS, _DESCRIPTION) 105 _DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION)
108 106
109 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION) 107 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION)
110 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION) 108 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION)
111 _ch_help_text = CreateHelpText(_CH_SYNOPSIS, _CH_DESCRIPTION) 109 _ch_help_text = CreateHelpText(_CH_SYNOPSIS, _CH_DESCRIPTION)
112 110
113 111
114 class DefAclCommand(Command): 112 class DefAclCommand(Command):
115 """Implementation of gsutil defacl command.""" 113 """Implementation of gsutil defacl command."""
116 114
117 # Command specification (processed by parent class). 115 # Command specification. See base class for documentation.
118 command_spec = { 116 command_spec = Command.CreateCommandSpec(
119 # Name of command. 117 'defacl',
120 COMMAND_NAME : 'defacl', 118 command_name_aliases=['setdefacl', 'getdefacl', 'chdefacl'],
121 # List of command name aliases. 119 min_args=2,
122 COMMAND_NAME_ALIASES : ['setdefacl', 'getdefacl', 'chdefacl'], 120 max_args=NO_MAX,
123 # Min number of args required by this command. 121 supported_sub_args='fg:u:d:',
124 MIN_ARGS : 2, 122 file_url_ok=False,
125 # Max number of args required by this command, or NO_MAX. 123 provider_url_ok=False,
126 MAX_ARGS : NO_MAX, 124 urls_start_arg=1,
127 # Getopt-style string specifying acceptable sub args. 125 gs_api_support=[ApiSelector.XML, ApiSelector.JSON],
128 SUPPORTED_SUB_ARGS : 'fg:u:d:', 126 gs_default_api=ApiSelector.JSON,
129 # True if file URIs acceptable for this command. 127 )
130 FILE_URIS_OK : False, 128 # Help specification. See help_provider.py for documentation.
131 # True if provider-only URIs acceptable for this command. 129 help_spec = Command.HelpSpec(
132 PROVIDER_URIS_OK : False, 130 help_name='defacl',
133 # Index in args of first URI arg. 131 help_name_aliases=[
134 URIS_START_ARG : 1, 132 'default acl', 'setdefacl', 'getdefacl', 'chdefacl'],
135 } 133 help_type='command_help',
136 help_spec = { 134 help_one_line_summary='Get, set, or change default ACL on buckets',
137 # Name of command or auxiliary help info for which this help applies. 135 help_text=_DETAILED_HELP_TEXT,
138 HELP_NAME : 'defacl', 136 subcommand_help_text={
139 # List of help name aliases. 137 'get': _get_help_text, 'set': _set_help_text, 'ch': _ch_help_text},
140 HELP_NAME_ALIASES : ['default acl', 'setdefacl', 'getdefacl', 'chdefacl'], 138 )
141 # Type of help:
142 HELP_TYPE : HelpType.COMMAND_HELP,
143 # One line summary of this help.
144 HELP_ONE_LINE_SUMMARY : 'Get, set, or change default ACL on buckets',
145 # The full help text.
146 HELP_TEXT : _detailed_help_text,
147 # Help text for sub-commands.
148 SUBCOMMAND_HELP_TEXT : {'get' : _get_help_text,
149 'set' : _set_help_text,
150 'ch' : _ch_help_text},
151 }
152 139
153 def _CalculateUrisStartArg(self): 140 def _CalculateUrlsStartArg(self):
154 if not self.args: 141 if not self.args:
155 self._RaiseWrongNumberOfArgumentsException() 142 self._RaiseWrongNumberOfArgumentsException()
156 if (self.args[0].lower() == 'set'): 143 if self.args[0].lower() == 'set':
157 return 2 144 return 2
158 elif self.command_alias_used == 'getdefacl': 145 elif self.command_alias_used == 'getdefacl':
159 return 0 146 return 0
160 else: 147 else:
161 return 1 148 return 1
162 149
163 def _SetDefAcl(self): 150 def _SetDefAcl(self):
164 if not self.suri_builder.StorageUri(self.args[-1]).names_bucket(): 151 if not StorageUrlFromString(self.args[-1]).IsBucket():
165 raise CommandException('URI must name a bucket for the %s command' % 152 raise CommandException('URL must name a bucket for the %s command' %
166 self.command_name) 153 self.command_name)
167 try: 154 try:
168 self.SetAclCommandHelper() 155 self.SetAclCommandHelper(SetAclFuncWrapper, SetAclExceptionHandler)
169 except GSResponseError as e: 156 except AccessDeniedException:
170 if e.code == 'AccessDenied' and e.reason == 'Forbidden' \ 157 self._WarnServiceAccounts()
171 and e.status == 403:
172 self._WarnServiceAccounts()
173 raise 158 raise
174 159
175 def _GetDefAcl(self): 160 def _GetDefAcl(self):
176 if not self.suri_builder.StorageUri(self.args[-1]).names_bucket(): 161 if not StorageUrlFromString(self.args[0]).IsBucket():
177 raise CommandException('URI must name a bucket for the %s command' % 162 raise CommandException('URL must name a bucket for the %s command' %
178 self.command_name) 163 self.command_name)
179 try: 164 self.GetAndPrintAcl(self.args[0])
180 self.GetAclCommandHelper()
181 except GSResponseError as e:
182 if e.code == 'AccessDenied' and e.reason == 'Forbidden' \
183 and e.status == 403:
184 self._WarnServiceAccounts()
185 raise
186 165
187 def _ChDefAcl(self): 166 def _ChDefAcl(self):
167 """Parses options and changes default object ACLs on specified buckets."""
168 self.parse_versions = True
188 self.changes = [] 169 self.changes = []
189 170
190 if self.sub_opts: 171 if self.sub_opts:
191 for o, a in self.sub_opts: 172 for o, a in self.sub_opts:
192 if o == '-g': 173 if o == '-g':
193 self.changes.append( 174 self.changes.append(
194 aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.GROUP)) 175 aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.GROUP))
195 if o == '-u': 176 if o == '-u':
196 self.changes.append( 177 self.changes.append(
197 aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.USER)) 178 aclhelpers.AclChange(a, scope_type=aclhelpers.ChangeType.USER))
198 if o == '-d': 179 if o == '-d':
199 self.changes.append(aclhelpers.AclDel(a)) 180 self.changes.append(aclhelpers.AclDel(a))
200 181
201 if not self.changes: 182 if not self.changes:
202 raise CommandException( 183 raise CommandException(
203 'Please specify at least one access change ' 184 'Please specify at least one access change '
204 'with the -g, -u, or -d flags') 185 'with the -g, -u, or -d flags')
205 186
206 storage_uri = self.UrisAreForSingleProvider(self.args) 187 if (not UrlsAreForSingleProvider(self.args) or
207 if not (storage_uri and storage_uri.get_provider().name == 'google'): 188 StorageUrlFromString(self.args[0]).scheme != 'gs'):
208 raise CommandException( 189 raise CommandException(
209 'The "{0}" command can only be used with gs:// URIs'.format( 190 'The "{0}" command can only be used with gs:// URLs'.format(
210 self.command_name)) 191 self.command_name))
211 192
212 bucket_uris = set() 193 bucket_urls = set()
213 for uri_arg in self.args: 194 for url_arg in self.args:
214 for result in self.WildcardIterator(uri_arg): 195 for result in self.WildcardIterator(url_arg):
215 uri = result.uri 196 if not result.storage_url.IsBucket():
216 if not uri.names_bucket():
217 raise CommandException( 197 raise CommandException(
218 'The defacl ch command can only be applied to buckets.') 198 'The defacl ch command can only be applied to buckets.')
219 bucket_uris.add(uri) 199 bucket_urls.add(result.storage_url)
220 200
221 for uri in bucket_uris: 201 for storage_url in bucket_urls:
222 self.ApplyAclChanges(uri) 202 self.ApplyAclChanges(storage_url)
223 203
224 @Retry(GSResponseError, tries=3, timeout_secs=1) 204 @Retry(ServiceException, tries=3, timeout_secs=1)
225 def ApplyAclChanges(self, uri): 205 def ApplyAclChanges(self, url):
226 """Applies the changes in self.changes to the provided URI.""" 206 """Applies the changes in self.changes to the provided URL."""
227 try: 207 bucket = self.gsutil_api.GetBucket(
228 current_acl = uri.get_def_acl() 208 url.bucket_name, provider=url.scheme,
229 except GSResponseError as e: 209 fields=['defaultObjectAcl', 'metageneration'])
230 if (e.code == 'AccessDenied' and e.reason == 'Forbidden' 210 current_acl = bucket.defaultObjectAcl
231 and e.status == 403): 211 if not current_acl:
232 self._WarnServiceAccounts() 212 self._WarnServiceAccounts()
233 self.logger.warning('Failed to set default acl for {0}: {1}' 213 self.logger.warning('Failed to set acl for %s. Please ensure you have '
234 .format(uri, e.reason)) 214 'OWNER-role access to this resource.', url)
235 return 215 return
236 216
237 modification_count = 0 217 modification_count = 0
238 for change in self.changes: 218 for change in self.changes:
239 modification_count += change.Execute(uri, current_acl, self.logger) 219 modification_count += change.Execute(
220 url, current_acl, 'defacl', self.logger)
240 if modification_count == 0: 221 if modification_count == 0:
241 self.logger.info('No changes to {0}'.format(uri)) 222 self.logger.info('No changes to %s', url)
242 return 223 return
243 224
244 # TODO: Add if-metageneration-match when boto provides access to bucket 225 try:
245 # metageneration. 226 preconditions = Preconditions(meta_gen_match=bucket.metageneration)
227 bucket_metadata = apitools_messages.Bucket(defaultObjectAcl=current_acl)
228 self.gsutil_api.PatchBucket(url.bucket_name, bucket_metadata,
229 preconditions=preconditions,
230 provider=url.scheme, fields=['id'])
231 except BadRequestException as e:
232 # Don't retry on bad requests, e.g. invalid email address.
233 raise CommandException('Received bad request from server: %s' % str(e))
246 234
247 # If this fails because of a precondition, it will raise a 235 self.logger.info('Updated default ACL on %s', url)
248 # GSResponseError for @Retry to handle.
249 try:
250 uri.set_def_acl(current_acl, validate=False)
251 except GSResponseError as e:
252 # Don't retry on bad requests, e.g. invalid email address.
253 if getattr(e, 'status', None) == 400:
254 raise CommandException('Received bad request from server: %s' % str(e))
255 raise
256 self.logger.info('Updated default ACL on {0}'.format(uri))
257 236
258 # Command entry point.
259 def RunCommand(self): 237 def RunCommand(self):
238 """Command entry point for the defacl command."""
260 action_subcommand = self.args.pop(0) 239 action_subcommand = self.args.pop(0)
261 (self.sub_opts, self.args) = getopt.getopt(self.args, 240 self.sub_opts, self.args = getopt.getopt(
262 self.command_spec[SUPPORTED_SUB_ARGS]) 241 self.args, self.command_spec.supported_sub_args)
263 self.CheckArguments() 242 self.CheckArguments()
243 self.def_acl = True
244 self.continue_on_error = False
264 if action_subcommand == 'get': 245 if action_subcommand == 'get':
265 func = self._GetDefAcl 246 func = self._GetDefAcl
266 elif action_subcommand == 'set': 247 elif action_subcommand == 'set':
267 func = self._SetDefAcl 248 func = self._SetDefAcl
268 elif action_subcommand in ('ch', 'change'): 249 elif action_subcommand in ('ch', 'change'):
269 func = self._ChDefAcl 250 func = self._ChDefAcl
270 else: 251 else:
271 raise CommandException(('Invalid subcommand "%s" for the %s command.\n' 252 raise CommandException(('Invalid subcommand "%s" for the %s command.\n'
272 'See "gsutil help defacl".') % 253 'See "gsutil help defacl".') %
273 (action_subcommand, self.command_name)) 254 (action_subcommand, self.command_name))
274 func() 255 func()
275 return 0 256 return 0
OLDNEW
« no previous file with comments | « gslib/commands/cp.py ('k') | gslib/commands/du.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698