OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 # Copyright 2014 Google Inc. All Rights Reserved. | 2 # Copyright 2014 Google Inc. All Rights Reserved. |
3 # | 3 # |
4 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
5 # 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. |
6 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
7 # | 7 # |
8 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
9 # | 9 # |
10 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
(...skipping 18 matching lines...) Expand all Loading... |
29 from boto.gs.acl import ALL_USERS | 29 from boto.gs.acl import ALL_USERS |
30 from boto.gs.acl import Entries | 30 from boto.gs.acl import Entries |
31 from boto.gs.acl import Entry | 31 from boto.gs.acl import Entry |
32 from boto.gs.acl import GROUP_BY_DOMAIN | 32 from boto.gs.acl import GROUP_BY_DOMAIN |
33 from boto.gs.acl import GROUP_BY_EMAIL | 33 from boto.gs.acl import GROUP_BY_EMAIL |
34 from boto.gs.acl import GROUP_BY_ID | 34 from boto.gs.acl import GROUP_BY_ID |
35 from boto.gs.acl import USER_BY_EMAIL | 35 from boto.gs.acl import USER_BY_EMAIL |
36 from boto.gs.acl import USER_BY_ID | 36 from boto.gs.acl import USER_BY_ID |
37 | 37 |
38 from gslib.cloud_api import ArgumentException | 38 from gslib.cloud_api import ArgumentException |
| 39 from gslib.cloud_api import BucketNotFoundException |
39 from gslib.cloud_api import NotFoundException | 40 from gslib.cloud_api import NotFoundException |
40 from gslib.cloud_api import Preconditions | 41 from gslib.cloud_api import Preconditions |
41 from gslib.exception import CommandException | 42 from gslib.exception import CommandException |
42 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m
essages | 43 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m
essages |
43 | 44 |
44 # In Python 2.6, ElementTree raises ExpatError instead of ParseError. | 45 # In Python 2.6, ElementTree raises ExpatError instead of ParseError. |
45 # pylint: disable=g-import-not-at-top | 46 # pylint: disable=g-import-not-at-top |
46 try: | 47 try: |
47 from xml.etree.ElementTree import ParseError as XmlParseError | 48 from xml.etree.ElementTree import ParseError as XmlParseError |
48 except ImportError: | 49 except ImportError: |
(...skipping 18 matching lines...) Expand all Loading... |
67 S3_ACL_MARKER_GUID = '3b89a6b5-b55a-4900-8c44-0b0a2f5eab43-s3-AclMarker' | 68 S3_ACL_MARKER_GUID = '3b89a6b5-b55a-4900-8c44-0b0a2f5eab43-s3-AclMarker' |
68 S3_DELETE_MARKER_GUID = 'eadeeee8-fa8c-49bb-8a7d-0362215932d8-s3-DeleteMarker' | 69 S3_DELETE_MARKER_GUID = 'eadeeee8-fa8c-49bb-8a7d-0362215932d8-s3-DeleteMarker' |
69 S3_MARKER_GUIDS = [S3_ACL_MARKER_GUID, S3_DELETE_MARKER_GUID] | 70 S3_MARKER_GUIDS = [S3_ACL_MARKER_GUID, S3_DELETE_MARKER_GUID] |
70 # This distinguishes S3 custom headers from S3 metadata on objects. | 71 # This distinguishes S3 custom headers from S3 metadata on objects. |
71 S3_HEADER_PREFIX = 'custom-amz-header' | 72 S3_HEADER_PREFIX = 'custom-amz-header' |
72 | 73 |
73 DEFAULT_CONTENT_TYPE = 'application/octet-stream' | 74 DEFAULT_CONTENT_TYPE = 'application/octet-stream' |
74 | 75 |
75 # Because CORS is just a list in apitools, we need special handling or blank | 76 # Because CORS is just a list in apitools, we need special handling or blank |
76 # CORS lists will get sent with other configuration commands such as lifecycle, | 77 # CORS lists will get sent with other configuration commands such as lifecycle, |
77 # commands, which would cause CORS configuration to be unintentionally removed. | 78 # which would cause CORS configuration to be unintentionally removed. |
78 # Protorpc defaults list values to an empty list, and won't allow us to set the | 79 # Protorpc defaults list values to an empty list, and won't allow us to set the |
79 # value to None like other configuration fields, so there is no way to | 80 # value to None like other configuration fields, so there is no way to |
80 # distinguish the default value from when we actually want to remove the CORS | 81 # distinguish the default value from when we actually want to remove the CORS |
81 # configuration. To work around this, we create a dummy CORS entry that | 82 # configuration. To work around this, we create a dummy CORS entry that |
82 # signifies that we should nullify the CORS configuration. | 83 # signifies that we should nullify the CORS configuration. |
83 # A value of [] means don't modify the CORS configuration. | 84 # A value of [] means don't modify the CORS configuration. |
84 # A value of REMOVE_CORS_CONFIG means remove the CORS configuration. | 85 # A value of REMOVE_CORS_CONFIG means remove the CORS configuration. |
85 REMOVE_CORS_CONFIG = [apitools_messages.Bucket.CorsValueListEntry( | 86 REMOVE_CORS_CONFIG = [apitools_messages.Bucket.CorsValueListEntry( |
86 maxAgeSeconds=-1, method=['REMOVE_CORS_CONFIG'])] | 87 maxAgeSeconds=-1, method=['REMOVE_CORS_CONFIG'])] |
87 | 88 |
| 89 # Similar to CORS above, we need a sentinel value allowing us to specify |
| 90 # when a default object ACL should be private (containing no entries). |
| 91 # A defaultObjectAcl value of [] means don't modify the default object ACL. |
| 92 # A value of [PRIVATE_DEFAULT_OBJ_ACL] means create an empty/private default |
| 93 # object ACL. |
| 94 PRIVATE_DEFAULT_OBJ_ACL = apitools_messages.ObjectAccessControl( |
| 95 id='PRIVATE_DEFAULT_OBJ_ACL') |
| 96 |
88 | 97 |
89 def ObjectMetadataFromHeaders(headers): | 98 def ObjectMetadataFromHeaders(headers): |
90 """Creates object metadata according to the provided headers. | 99 """Creates object metadata according to the provided headers. |
91 | 100 |
92 gsutil -h allows specifiying various headers (originally intended | 101 gsutil -h allows specifiying various headers (originally intended |
93 to be passed to boto in gsutil v3). For the JSON API to be compatible with | 102 to be passed to boto in gsutil v3). For the JSON API to be compatible with |
94 this option, we need to parse these headers into gsutil_api Object fields. | 103 this option, we need to parse these headers into gsutil_api Object fields. |
95 | 104 |
96 Args: | 105 Args: |
97 headers: Dict of headers passed via gsutil -h | 106 headers: Dict of headers passed via gsutil -h |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 if GOOG_METAGENERATION_MATCH_REGEX.match(header): | 314 if GOOG_METAGENERATION_MATCH_REGEX.match(header): |
306 return_preconditions.meta_gen_match = long(value) | 315 return_preconditions.meta_gen_match = long(value) |
307 except ValueError, _: | 316 except ValueError, _: |
308 raise ArgumentException('Invalid precondition header specified. ' | 317 raise ArgumentException('Invalid precondition header specified. ' |
309 'x-goog-if-generation-match and ' | 318 'x-goog-if-generation-match and ' |
310 'x-goog-if-metageneration match must be specified ' | 319 'x-goog-if-metageneration match must be specified ' |
311 'with a positive integer value.') | 320 'with a positive integer value.') |
312 return return_preconditions | 321 return return_preconditions |
313 | 322 |
314 | 323 |
| 324 def CreateNotFoundExceptionForObjectWrite( |
| 325 dst_provider, dst_bucket_name, src_provider=None, |
| 326 src_bucket_name=None, src_object_name=None, src_generation=None): |
| 327 """Creates a NotFoundException for an object upload or copy. |
| 328 |
| 329 This is necessary because 404s don't necessarily specify which resource |
| 330 does not exist. |
| 331 |
| 332 Args: |
| 333 dst_provider: String abbreviation of destination provider, e.g., 'gs'. |
| 334 dst_bucket_name: Destination bucket name for the write operation. |
| 335 src_provider: String abbreviation of source provider, i.e. 'gs', if any. |
| 336 src_bucket_name: Source bucket name, if any (for the copy case). |
| 337 src_object_name: Source object name, if any (for the copy case). |
| 338 src_generation: Source object generation, if any (for the copy case). |
| 339 |
| 340 Returns: |
| 341 NotFoundException with appropriate message. |
| 342 """ |
| 343 dst_url_string = '%s://%s' % (dst_provider, dst_bucket_name) |
| 344 if src_bucket_name and src_object_name: |
| 345 src_url_string = '%s://%s/%s' % (src_provider, src_bucket_name, |
| 346 src_object_name) |
| 347 if src_generation: |
| 348 src_url_string += '#%s' % str(src_generation) |
| 349 return NotFoundException( |
| 350 'The source object %s or the destination bucket %s does not exist.' % |
| 351 (src_url_string, dst_url_string)) |
| 352 |
| 353 return NotFoundException( |
| 354 'The destination bucket %s does not exist or the write to the ' |
| 355 'destination must be restarted' % dst_url_string) |
| 356 |
| 357 |
315 def CreateBucketNotFoundException(code, provider, bucket_name): | 358 def CreateBucketNotFoundException(code, provider, bucket_name): |
316 return NotFoundException('%s://%s bucket does not exist.' % | 359 return BucketNotFoundException('%s://%s bucket does not exist.' % |
317 (provider, bucket_name), status=code) | 360 (provider, bucket_name), bucket_name, |
| 361 status=code) |
318 | 362 |
319 | 363 |
320 def CreateObjectNotFoundException(code, provider, bucket_name, object_name, | 364 def CreateObjectNotFoundException(code, provider, bucket_name, object_name, |
321 generation=None): | 365 generation=None): |
322 uri_string = '%s://%s/%s' % (provider, bucket_name, object_name) | 366 uri_string = '%s://%s/%s' % (provider, bucket_name, object_name) |
323 if generation: | 367 if generation: |
324 uri_string += '#%s' % str(generation) | 368 uri_string += '#%s' % str(generation) |
325 return NotFoundException('%s does not exist.' % uri_string, status=code) | 369 return NotFoundException('%s does not exist.' % uri_string, status=code) |
326 | 370 |
327 | 371 |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
631 acl = ACL() | 675 acl = ACL() |
632 acl.parent = None | 676 acl.parent = None |
633 acl.entries = cls.BotoEntriesFromJson(acl_json, acl) | 677 acl.entries = cls.BotoEntriesFromJson(acl_json, acl) |
634 return acl | 678 return acl |
635 | 679 |
636 @classmethod | 680 @classmethod |
637 # acl_message is a list of messages, either object or bucketaccesscontrol | 681 # acl_message is a list of messages, either object or bucketaccesscontrol |
638 def BotoAclFromMessage(cls, acl_message): | 682 def BotoAclFromMessage(cls, acl_message): |
639 acl_dicts = [] | 683 acl_dicts = [] |
640 for message in acl_message: | 684 for message in acl_message: |
| 685 if message == PRIVATE_DEFAULT_OBJ_ACL: |
| 686 # Sentinel value indicating acl_dicts should be an empty list to create |
| 687 # a private (no entries) default object ACL. |
| 688 break |
641 acl_dicts.append(encoding.MessageToDict(message)) | 689 acl_dicts.append(encoding.MessageToDict(message)) |
642 return cls.BotoAclFromJson(acl_dicts) | 690 return cls.BotoAclFromJson(acl_dicts) |
643 | 691 |
644 @classmethod | 692 @classmethod |
645 def BotoAclToJson(cls, acl): | 693 def BotoAclToJson(cls, acl): |
646 if hasattr(acl, 'entries'): | 694 if hasattr(acl, 'entries'): |
647 return cls.BotoEntriesToJson(acl.entries) | 695 return cls.BotoEntriesToJson(acl.entries) |
648 return [] | 696 return [] |
649 | 697 |
650 @classmethod | 698 @classmethod |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
782 acl_entry.object = None | 830 acl_entry.object = None |
783 acl_entry.generation = None | 831 acl_entry.generation = None |
784 acl_entry.kind = None | 832 acl_entry.kind = None |
785 acl_entry.bucket = None | 833 acl_entry.bucket = None |
786 acl_entry.id = None | 834 acl_entry.id = None |
787 acl_entry.selfLink = None | 835 acl_entry.selfLink = None |
788 acl_entry.etag = None | 836 acl_entry.etag = None |
789 serializable_acl.append(encoding.MessageToDict(acl_entry)) | 837 serializable_acl.append(encoding.MessageToDict(acl_entry)) |
790 return json.dumps(serializable_acl, sort_keys=True, | 838 return json.dumps(serializable_acl, sort_keys=True, |
791 indent=2, separators=(',', ': ')) | 839 indent=2, separators=(',', ': ')) |
OLD | NEW |