swift 2.32.0__py2.py3-none-any.whl → 2.34.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. swift/account/auditor.py +11 -0
  2. swift/account/reaper.py +11 -1
  3. swift/account/replicator.py +22 -0
  4. swift/account/server.py +13 -12
  5. swift-2.32.0.data/scripts/swift-account-audit → swift/cli/account_audit.py +6 -2
  6. swift-2.32.0.data/scripts/swift-config → swift/cli/config.py +1 -1
  7. swift-2.32.0.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +6 -2
  8. swift-2.32.0.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +12 -3
  9. swift-2.32.0.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +6 -2
  10. swift/cli/info.py +131 -3
  11. swift-2.32.0.data/scripts/swift-oldies → swift/cli/oldies.py +6 -3
  12. swift-2.32.0.data/scripts/swift-orphans → swift/cli/orphans.py +7 -2
  13. swift-2.32.0.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +9 -18
  14. swift-2.32.0.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
  15. swift/cli/relinker.py +1 -1
  16. swift/cli/reload.py +141 -0
  17. swift/cli/ringbuilder.py +24 -0
  18. swift/common/daemon.py +12 -2
  19. swift/common/db.py +14 -9
  20. swift/common/db_auditor.py +2 -2
  21. swift/common/db_replicator.py +6 -0
  22. swift/common/exceptions.py +12 -0
  23. swift/common/http_protocol.py +76 -3
  24. swift/common/manager.py +120 -5
  25. swift/common/memcached.py +24 -25
  26. swift/common/middleware/account_quotas.py +144 -43
  27. swift/common/middleware/backend_ratelimit.py +166 -24
  28. swift/common/middleware/catch_errors.py +1 -3
  29. swift/common/middleware/cname_lookup.py +3 -5
  30. swift/common/middleware/container_sync.py +6 -10
  31. swift/common/middleware/crypto/crypto_utils.py +4 -5
  32. swift/common/middleware/crypto/decrypter.py +4 -5
  33. swift/common/middleware/crypto/kms_keymaster.py +2 -1
  34. swift/common/middleware/proxy_logging.py +57 -43
  35. swift/common/middleware/ratelimit.py +6 -7
  36. swift/common/middleware/recon.py +6 -7
  37. swift/common/middleware/s3api/acl_handlers.py +10 -1
  38. swift/common/middleware/s3api/controllers/__init__.py +3 -0
  39. swift/common/middleware/s3api/controllers/acl.py +3 -2
  40. swift/common/middleware/s3api/controllers/logging.py +2 -2
  41. swift/common/middleware/s3api/controllers/multi_upload.py +31 -15
  42. swift/common/middleware/s3api/controllers/obj.py +20 -1
  43. swift/common/middleware/s3api/controllers/object_lock.py +44 -0
  44. swift/common/middleware/s3api/s3api.py +6 -0
  45. swift/common/middleware/s3api/s3request.py +190 -74
  46. swift/common/middleware/s3api/s3response.py +48 -8
  47. swift/common/middleware/s3api/s3token.py +2 -2
  48. swift/common/middleware/s3api/utils.py +2 -1
  49. swift/common/middleware/slo.py +508 -310
  50. swift/common/middleware/staticweb.py +45 -14
  51. swift/common/middleware/tempauth.py +6 -4
  52. swift/common/middleware/tempurl.py +134 -93
  53. swift/common/middleware/x_profile/exceptions.py +1 -4
  54. swift/common/middleware/x_profile/html_viewer.py +9 -10
  55. swift/common/middleware/x_profile/profile_model.py +1 -2
  56. swift/common/middleware/xprofile.py +1 -2
  57. swift/common/request_helpers.py +101 -8
  58. swift/common/statsd_client.py +207 -0
  59. swift/common/storage_policy.py +1 -1
  60. swift/common/swob.py +5 -2
  61. swift/common/utils/__init__.py +331 -1774
  62. swift/common/utils/base.py +138 -0
  63. swift/common/utils/config.py +443 -0
  64. swift/common/utils/logs.py +999 -0
  65. swift/common/utils/timestamp.py +23 -2
  66. swift/common/wsgi.py +19 -3
  67. swift/container/auditor.py +11 -0
  68. swift/container/backend.py +136 -31
  69. swift/container/reconciler.py +11 -2
  70. swift/container/replicator.py +64 -7
  71. swift/container/server.py +276 -146
  72. swift/container/sharder.py +86 -42
  73. swift/container/sync.py +11 -1
  74. swift/container/updater.py +12 -2
  75. swift/obj/auditor.py +20 -3
  76. swift/obj/diskfile.py +63 -25
  77. swift/obj/expirer.py +154 -47
  78. swift/obj/mem_diskfile.py +2 -1
  79. swift/obj/mem_server.py +1 -0
  80. swift/obj/reconstructor.py +28 -4
  81. swift/obj/replicator.py +63 -24
  82. swift/obj/server.py +76 -59
  83. swift/obj/updater.py +12 -2
  84. swift/obj/watchers/dark_data.py +72 -34
  85. swift/proxy/controllers/account.py +3 -2
  86. swift/proxy/controllers/base.py +254 -148
  87. swift/proxy/controllers/container.py +274 -289
  88. swift/proxy/controllers/obj.py +120 -166
  89. swift/proxy/server.py +17 -13
  90. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/AUTHORS +14 -4
  91. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/METADATA +9 -7
  92. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/RECORD +97 -120
  93. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/entry_points.txt +39 -0
  94. swift-2.34.0.dist-info/pbr.json +1 -0
  95. swift-2.32.0.data/scripts/swift-account-auditor +0 -23
  96. swift-2.32.0.data/scripts/swift-account-info +0 -52
  97. swift-2.32.0.data/scripts/swift-account-reaper +0 -23
  98. swift-2.32.0.data/scripts/swift-account-replicator +0 -34
  99. swift-2.32.0.data/scripts/swift-account-server +0 -23
  100. swift-2.32.0.data/scripts/swift-container-auditor +0 -23
  101. swift-2.32.0.data/scripts/swift-container-info +0 -56
  102. swift-2.32.0.data/scripts/swift-container-reconciler +0 -21
  103. swift-2.32.0.data/scripts/swift-container-replicator +0 -34
  104. swift-2.32.0.data/scripts/swift-container-server +0 -23
  105. swift-2.32.0.data/scripts/swift-container-sharder +0 -37
  106. swift-2.32.0.data/scripts/swift-container-sync +0 -23
  107. swift-2.32.0.data/scripts/swift-container-updater +0 -23
  108. swift-2.32.0.data/scripts/swift-dispersion-report +0 -24
  109. swift-2.32.0.data/scripts/swift-form-signature +0 -20
  110. swift-2.32.0.data/scripts/swift-init +0 -119
  111. swift-2.32.0.data/scripts/swift-object-auditor +0 -29
  112. swift-2.32.0.data/scripts/swift-object-expirer +0 -33
  113. swift-2.32.0.data/scripts/swift-object-info +0 -60
  114. swift-2.32.0.data/scripts/swift-object-reconstructor +0 -33
  115. swift-2.32.0.data/scripts/swift-object-relinker +0 -23
  116. swift-2.32.0.data/scripts/swift-object-replicator +0 -37
  117. swift-2.32.0.data/scripts/swift-object-server +0 -27
  118. swift-2.32.0.data/scripts/swift-object-updater +0 -23
  119. swift-2.32.0.data/scripts/swift-proxy-server +0 -23
  120. swift-2.32.0.data/scripts/swift-recon +0 -24
  121. swift-2.32.0.data/scripts/swift-ring-builder +0 -37
  122. swift-2.32.0.data/scripts/swift-ring-builder-analyzer +0 -22
  123. swift-2.32.0.data/scripts/swift-ring-composer +0 -22
  124. swift-2.32.0.dist-info/pbr.json +0 -1
  125. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/LICENSE +0 -0
  126. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/WHEEL +0 -0
  127. {swift-2.32.0.dist-info → swift-2.34.0.dist-info}/top_level.txt +0 -0
swift/container/server.py CHANGED
@@ -15,6 +15,7 @@
15
15
 
16
16
  import json
17
17
  import os
18
+ import sys
18
19
  import time
19
20
  import traceback
20
21
 
@@ -38,7 +39,7 @@ from swift.common.utils import get_logger, hash_path, public, \
38
39
  config_true_value, timing_stats, replication, \
39
40
  override_bytes_from_content_type, get_log_line, \
40
41
  config_fallocate_value, fs_has_free_space, list_from_csv, \
41
- ShardRange
42
+ ShardRange, parse_options
42
43
  from swift.common.constraints import valid_timestamp, check_utf8, \
43
44
  check_drive, AUTO_CREATE_ACCOUNT_PREFIX
44
45
  from swift.common.bufferedhttp import http_connect
@@ -53,6 +54,7 @@ from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPConflict, \
53
54
  HTTPPreconditionFailed, HTTPMethodNotAllowed, Request, Response, \
54
55
  HTTPInsufficientStorage, HTTPException, HTTPMovedPermanently, \
55
56
  wsgi_to_str, str_to_wsgi
57
+ from swift.common.wsgi import run_wsgi
56
58
 
57
59
 
58
60
  def gen_resp_headers(info, is_deleted=False):
@@ -141,17 +143,7 @@ class ContainerController(BaseStorageServer):
141
143
  self.replicator_rpc = ContainerReplicatorRpc(
142
144
  self.root, DATADIR, ContainerBroker, self.mount_check,
143
145
  logger=self.logger)
144
- if conf.get('auto_create_account_prefix'):
145
- self.logger.warning('Option auto_create_account_prefix is '
146
- 'deprecated. Configure '
147
- 'auto_create_account_prefix under the '
148
- 'swift-constraints section of '
149
- 'swift.conf. This option will '
150
- 'be ignored in a future release.')
151
- self.auto_create_account_prefix = \
152
- conf['auto_create_account_prefix']
153
- else:
154
- self.auto_create_account_prefix = AUTO_CREATE_ACCOUNT_PREFIX
146
+ self.auto_create_account_prefix = AUTO_CREATE_ACCOUNT_PREFIX
155
147
  self.shards_account_prefix = (
156
148
  self.auto_create_account_prefix + 'shards_')
157
149
  if config_true_value(conf.get('allow_versions', 'f')):
@@ -511,59 +503,42 @@ class ContainerController(BaseStorageServer):
511
503
  return HTTPInsufficientStorage(drive=drive, request=req)
512
504
  if not self.check_free_space(drive):
513
505
  return HTTPInsufficientStorage(drive=drive, request=req)
514
- requested_policy_index = self.get_and_validate_policy_index(req)
515
- broker = self._get_container_broker(drive, part, account, container)
516
- if obj: # put container object
517
- # obj put expects the policy_index header, default is for
518
- # legacy support during upgrade.
519
- obj_policy_index = requested_policy_index or 0
520
- self._maybe_autocreate(
521
- broker, req_timestamp, account, obj_policy_index, req)
522
- # redirect if a shard exists for this object name
523
- response = self._redirect_to_shard(req, broker, obj)
524
- if response:
525
- return response
526
-
527
- broker.put_object(obj, req_timestamp.internal,
528
- int(req.headers['x-size']),
529
- wsgi_to_str(req.headers['x-content-type']),
530
- wsgi_to_str(req.headers['x-etag']), 0,
531
- obj_policy_index,
532
- wsgi_to_str(req.headers.get(
533
- 'x-content-type-timestamp')),
534
- wsgi_to_str(req.headers.get('x-meta-timestamp')))
535
- return HTTPCreated(request=req)
536
506
 
507
+ broker = self._get_container_broker(drive, part, account, container)
508
+ if obj:
509
+ return self.PUT_object(req, broker, account, obj, req_timestamp)
537
510
  record_type = req.headers.get('x-backend-record-type', '').lower()
538
511
  if record_type == RECORD_TYPE_SHARD:
539
- try:
540
- # validate incoming data...
541
- shard_ranges = [ShardRange.from_dict(sr)
542
- for sr in json.loads(req.body)]
543
- except (ValueError, KeyError, TypeError) as err:
544
- return HTTPBadRequest('Invalid body: %r' % err)
545
- created = self._maybe_autocreate(
546
- broker, req_timestamp, account, requested_policy_index, req)
547
- self._update_metadata(req, broker, req_timestamp, 'PUT')
548
- if shard_ranges:
549
- # TODO: consider writing the shard ranges into the pending
550
- # file, but if so ensure an all-or-none semantic for the write
551
- broker.merge_shard_ranges(shard_ranges)
552
- else: # put container
553
- if requested_policy_index is None:
554
- # use the default index sent by the proxy if available
555
- new_container_policy = req.headers.get(
556
- 'X-Backend-Storage-Policy-Default', int(POLICIES.default))
557
- else:
558
- new_container_policy = requested_policy_index
559
- created = self._update_or_create(req, broker,
560
- req_timestamp.internal,
561
- new_container_policy,
562
- requested_policy_index)
563
- self._update_metadata(req, broker, req_timestamp, 'PUT')
564
- resp = self.account_update(req, account, container, broker)
565
- if resp:
566
- return resp
512
+ return self.PUT_shard(req, broker, account, req_timestamp)
513
+ else:
514
+ return self.PUT_container(req, broker, account,
515
+ container, req_timestamp)
516
+
517
+ @timing_stats()
518
+ def PUT_object(self, req, broker, account, obj, req_timestamp):
519
+ """Put object into container."""
520
+ # obj put expects the policy_index header, default is for
521
+ # legacy support during upgrade.
522
+ requested_policy_index = self.get_and_validate_policy_index(req)
523
+ obj_policy_index = requested_policy_index or 0
524
+ self._maybe_autocreate(
525
+ broker, req_timestamp, account, obj_policy_index, req)
526
+ # redirect if a shard exists for this object name
527
+ response = self._redirect_to_shard(req, broker, obj)
528
+ if response:
529
+ return response
530
+
531
+ broker.put_object(obj, req_timestamp.internal,
532
+ int(req.headers['x-size']),
533
+ wsgi_to_str(req.headers['x-content-type']),
534
+ wsgi_to_str(req.headers['x-etag']), 0,
535
+ obj_policy_index,
536
+ wsgi_to_str(req.headers.get(
537
+ 'x-content-type-timestamp')),
538
+ wsgi_to_str(req.headers.get('x-meta-timestamp')))
539
+ return HTTPCreated(request=req)
540
+
541
+ def _create_ok_resp(self, req, broker, created):
567
542
  if created:
568
543
  return HTTPCreated(request=req,
569
544
  headers={'x-backend-storage-policy-index':
@@ -573,6 +548,45 @@ class ContainerController(BaseStorageServer):
573
548
  headers={'x-backend-storage-policy-index':
574
549
  broker.storage_policy_index})
575
550
 
551
+ @timing_stats()
552
+ def PUT_shard(self, req, broker, account, req_timestamp):
553
+ """Put shards into container."""
554
+ requested_policy_index = self.get_and_validate_policy_index(req)
555
+ try:
556
+ # validate incoming data...
557
+ shard_ranges = [ShardRange.from_dict(sr)
558
+ for sr in json.loads(req.body)]
559
+ except (ValueError, KeyError, TypeError) as err:
560
+ return HTTPBadRequest('Invalid body: %r' % err)
561
+ created = self._maybe_autocreate(
562
+ broker, req_timestamp, account, requested_policy_index, req)
563
+ self._update_metadata(req, broker, req_timestamp, 'PUT')
564
+ if shard_ranges:
565
+ # TODO: consider writing the shard ranges into the pending
566
+ # file, but if so ensure an all-or-none semantic for the write
567
+ broker.merge_shard_ranges(shard_ranges)
568
+ return self._create_ok_resp(req, broker, created)
569
+
570
+ @timing_stats()
571
+ def PUT_container(self, req, broker, account, container, req_timestamp):
572
+ """Update or create container."""
573
+ requested_policy_index = self.get_and_validate_policy_index(req)
574
+ if requested_policy_index is None:
575
+ # use the default index sent by the proxy if available
576
+ new_container_policy = req.headers.get(
577
+ 'X-Backend-Storage-Policy-Default', int(POLICIES.default))
578
+ else:
579
+ new_container_policy = requested_policy_index
580
+ created = self._update_or_create(req, broker,
581
+ req_timestamp.internal,
582
+ new_container_policy,
583
+ requested_policy_index)
584
+ self._update_metadata(req, broker, req_timestamp, 'PUT')
585
+ resp = self.account_update(req, account, container, broker)
586
+ if resp:
587
+ return resp
588
+ return self._create_ok_resp(req, broker, created)
589
+
576
590
  @public
577
591
  @timing_stats(sample_rate=0.1)
578
592
  def HEAD(self, req):
@@ -600,29 +614,42 @@ class ContainerController(BaseStorageServer):
600
614
  resp.last_modified = Timestamp(headers['X-PUT-Timestamp']).ceil()
601
615
  return resp
602
616
 
603
- def update_data_record(self, record):
617
+ def update_shard_record(self, record, shard_record_full=True):
618
+ """
619
+ Return the shard_range database record as a dict, the keys will depend
620
+ on the database fields provided in the record.
621
+
622
+ :param record: shard entry record, either ShardRange or Namespace.
623
+ :param shard_record_full: boolean, when true the timestamp field is
624
+ added as "last_modified" in iso format.
625
+ :returns: dict suitable for listing responses
604
626
  """
605
- Perform any mutations to container listing records that are common to
606
- all serialization formats, and returns it as a dict.
627
+ response = dict(record)
628
+ if shard_record_full:
629
+ created = record.timestamp
630
+ response['last_modified'] = Timestamp(created).isoformat
631
+ return response
632
+
633
+ def update_object_record(self, record):
634
+ """
635
+ Perform mutation to container listing records that are common to all
636
+ serialization formats, and returns it as a dict.
607
637
 
608
638
  Converts created time to iso timestamp.
609
639
  Replaces size with 'swift_bytes' content type parameter.
610
640
 
611
- :params record: object entry record
641
+ :param record: object entry record
612
642
  :returns: modified record
613
643
  """
614
- if isinstance(record, ShardRange):
615
- created = record.timestamp
616
- response = dict(record)
617
- else:
618
- (name, created, size, content_type, etag) = record[:5]
619
- name_ = name.decode('utf8') if six.PY2 else name
620
- if content_type is None:
621
- return {'subdir': name_}
622
- response = {
623
- 'bytes': size, 'hash': etag, 'name': name_,
624
- 'content_type': content_type}
625
- override_bytes_from_content_type(response, logger=self.logger)
644
+ # record is object info
645
+ (name, created, size, content_type, etag) = record[:5]
646
+ name_ = name.decode('utf8') if six.PY2 else name
647
+ if content_type is None:
648
+ return {'subdir': name_}
649
+ response = {
650
+ 'bytes': size, 'hash': etag, 'name': name_,
651
+ 'content_type': content_type}
652
+ override_bytes_from_content_type(response, logger=self.logger)
626
653
  response['last_modified'] = Timestamp(created).isoformat
627
654
  return response
628
655
 
@@ -685,11 +712,11 @@ class ContainerController(BaseStorageServer):
685
712
  either the string or integer representation of
686
713
  :data:`~swift.common.utils.ShardRange.STATES`.
687
714
 
688
- Two alias values may be used in a ``states`` parameter value:
689
- ``listing`` will cause the listing to include all shard ranges in a
690
- state suitable for contributing to an object listing; ``updating``
691
- will cause the listing to include all shard ranges in a state
692
- suitable to accept an object update.
715
+ Alias values may be used in a ``states`` parameter value. The
716
+ ``listing`` alias will cause the listing to include all shard ranges
717
+ in a state suitable for contributing to an object listing. The
718
+ ``updating`` alias will cause the listing to include all shard ranges
719
+ in a state suitable to accept an object update.
693
720
 
694
721
  If either of these aliases is used then the shard range listing will
695
722
  if necessary be extended with a synthesised 'filler' range in order
@@ -698,6 +725,23 @@ class ContainerController(BaseStorageServer):
698
725
  uncovered tail of the requested name range and will point back to the
699
726
  same container.
700
727
 
728
+ The ``auditing`` alias will cause the listing to include all shard
729
+ ranges in a state useful to the sharder while auditing a shard
730
+ container. This alias will not cause a 'filler' range to be added,
731
+ but will cause the container's own shard range to be included in the
732
+ listing. For now, ``auditing`` is only supported when
733
+ 'X-Backend-Record-Shard-Format' is 'full'.
734
+
735
+ * Shard range listings can be simplified to include only Namespace
736
+ only attributes (name, lower and upper) if the caller send the header
737
+ ``X-Backend-Record-Shard-Format`` with value 'namespace' as a hint
738
+ that it would prefer namespaces. If this header doesn't exist or the
739
+ value is 'full', the listings will default to include all attributes
740
+ of shard ranges. But if params has includes/marker/end_marker then
741
+ the response will be full shard ranges, regardless the header of
742
+ ``X-Backend-Record-Shard-Format``. The response header
743
+ ``X-Backend-Record-Type`` will tell the user what type it gets back.
744
+
701
745
  * Listings are not normally returned from a deleted container. However,
702
746
  the ``X-Backend-Override-Deleted`` header may be used with a value in
703
747
  :attr:`swift.common.utils.TRUE_VALUES` to force a shard range
@@ -709,13 +753,6 @@ class ContainerController(BaseStorageServer):
709
753
  """
710
754
  drive, part, account, container, obj = get_obj_name_and_placement(req)
711
755
  params = validate_container_params(req)
712
- path = params.get('path')
713
- prefix = params.get('prefix')
714
- delimiter = params.get('delimiter')
715
- marker = params.get('marker', '')
716
- end_marker = params.get('end_marker')
717
- limit = params['limit']
718
- reverse = config_true_value(params.get('reverse'))
719
756
  out_content_type = listing_formats.get_listing_content_type(req)
720
757
  try:
721
758
  check_drive(self.root, drive, self.mount_check)
@@ -730,70 +767,154 @@ class ContainerController(BaseStorageServer):
730
767
  if record_type == 'auto' and db_state in (SHARDING, SHARDED):
731
768
  record_type = 'shard'
732
769
  if record_type == 'shard':
733
- override_deleted = info and config_true_value(
734
- req.headers.get('x-backend-override-deleted', False))
735
- resp_headers = gen_resp_headers(
736
- info, is_deleted=is_deleted and not override_deleted)
737
- if is_deleted and not override_deleted:
738
- return HTTPNotFound(request=req, headers=resp_headers)
739
- resp_headers['X-Backend-Record-Type'] = 'shard'
740
- includes = params.get('includes')
741
- override_filter_hdr = req.headers.get(
742
- 'x-backend-override-shard-name-filter', '').lower()
743
- if override_filter_hdr == db_state == 'sharded':
744
- # respect the request to send back *all* ranges if the db is in
745
- # sharded state
746
- resp_headers['X-Backend-Override-Shard-Name-Filter'] = 'true'
747
- marker = end_marker = includes = None
748
- reverse = False
749
- states = params.get('states')
750
- fill_gaps = include_own = False
751
- if states:
752
- states = list_from_csv(states)
753
- fill_gaps = any(('listing' in states, 'updating' in states))
754
- # 'auditing' is used during shard audit; if the shard is
755
- # shrinking then it needs to get acceptor shard ranges, which
756
- # may be the root container itself, so use include_own
757
- include_own = 'auditing' in states
758
- try:
759
- states = broker.resolve_shard_range_states(states)
760
- except ValueError:
761
- return HTTPBadRequest(request=req, body='Bad state')
762
- include_deleted = config_true_value(
763
- req.headers.get('x-backend-include-deleted', False))
770
+ return self.GET_shard(req, broker, container, params, info,
771
+ is_deleted, out_content_type)
772
+ else:
773
+ return self.GET_object(req, broker, container, params, info,
774
+ is_deleted, out_content_type)
775
+
776
+ @timing_stats()
777
+ def GET_shard(self, req, broker, container, params, info,
778
+ is_deleted, out_content_type):
779
+ """
780
+ Returns a list of persisted shard ranges or namespaces in response.
781
+
782
+ :param req: swob.Request object
783
+ :param broker: container DB broker object
784
+ :param container: container name
785
+ :param params: the request params.
786
+ :param info: the global info for the container
787
+ :param is_deleted: the is_deleted status for the container.
788
+ :param out_content_type: content type as a string.
789
+ :returns: an instance of :class:`swift.common.swob.Response`
790
+ """
791
+ override_deleted = info and config_true_value(
792
+ req.headers.get('x-backend-override-deleted', False))
793
+ resp_headers = gen_resp_headers(
794
+ info, is_deleted=is_deleted and not override_deleted)
795
+
796
+ if is_deleted and not override_deleted:
797
+ return HTTPNotFound(request=req, headers=resp_headers)
798
+
799
+ marker = params.get('marker', '')
800
+ end_marker = params.get('end_marker')
801
+ reverse = config_true_value(params.get('reverse'))
802
+ states = params.get('states')
803
+ includes = params.get('includes')
804
+ include_deleted = config_true_value(
805
+ req.headers.get('x-backend-include-deleted', False))
806
+
807
+ resp_headers['X-Backend-Record-Type'] = 'shard'
808
+ override_filter_hdr = req.headers.get(
809
+ 'x-backend-override-shard-name-filter', '').lower()
810
+ if override_filter_hdr == info.get('db_state') == 'sharded':
811
+ # respect the request to send back *all* ranges if the db is in
812
+ # sharded state
813
+ resp_headers['X-Backend-Override-Shard-Name-Filter'] = 'true'
814
+ marker = end_marker = includes = None
815
+ reverse = False
816
+ fill_gaps = include_own = False
817
+ if states:
818
+ states = list_from_csv(states)
819
+ fill_gaps = any(('listing' in states, 'updating' in states))
820
+ # The 'auditing' state alias is used by the sharder during
821
+ # shard audit; if the shard is shrinking then it needs to get
822
+ # acceptor shard ranges, which may be the root container
823
+ # itself, so use include_own.
824
+ include_own = 'auditing' in states
825
+ try:
826
+ states = broker.resolve_shard_range_states(states)
827
+ except ValueError:
828
+ return HTTPBadRequest(request=req, body='Bad state')
829
+
830
+ # For record type of 'shard', user can specify an additional header
831
+ # to ask for list of Namespaces instead of full ShardRanges.
832
+ # This will allow proxy server who is going to retrieve Namespace
833
+ # to talk to older version of container servers who don't support
834
+ # Namespace yet during upgrade.
835
+ shard_format = req.headers.get(
836
+ 'x-backend-record-shard-format', 'full').lower()
837
+ if shard_format == 'namespace':
838
+ resp_headers['X-Backend-Record-Shard-Format'] = 'namespace'
839
+ # Namespace GET does not support all the options of Shard Range
840
+ # GET: 'x-backend-include-deleted' cannot be supported because
841
+ # there is no way for a Namespace to indicate the deleted state;
842
+ # the 'auditing' state query parameter is not supported because it
843
+ # is specific to the sharder which only requests full shard ranges.
844
+ if include_deleted:
845
+ return HTTPBadRequest(
846
+ request=req, body='No include_deleted for namespace GET')
847
+ if include_own:
848
+ return HTTPBadRequest(
849
+ request=req, body='No auditing state for namespace GET')
850
+ shard_format_full = False
851
+ container_list = broker.get_namespaces(
852
+ marker, end_marker, includes, reverse, states, fill_gaps)
853
+ else:
854
+ resp_headers['X-Backend-Record-Shard-Format'] = 'full'
855
+ shard_format_full = True
764
856
  container_list = broker.get_shard_ranges(
765
857
  marker, end_marker, includes, reverse, states=states,
766
858
  include_deleted=include_deleted, fill_gaps=fill_gaps,
767
859
  include_own=include_own)
768
- else:
769
- requested_policy_index = self.get_and_validate_policy_index(req)
770
- resp_headers = gen_resp_headers(info, is_deleted=is_deleted)
771
- if is_deleted:
772
- return HTTPNotFound(request=req, headers=resp_headers)
773
- resp_headers['X-Backend-Record-Type'] = 'object'
774
- storage_policy_index = (
775
- requested_policy_index if requested_policy_index is not None
776
- else info['storage_policy_index'])
777
- resp_headers['X-Backend-Record-Storage-Policy-Index'] = \
778
- storage_policy_index
779
- # Use the retired db while container is in process of sharding,
780
- # otherwise use current db
781
- src_broker = broker.get_brokers()[0]
782
- container_list = src_broker.list_objects_iter(
783
- limit, marker, end_marker, prefix, delimiter, path,
784
- storage_policy_index=storage_policy_index,
785
- reverse=reverse, allow_reserved=req.allow_reserved_names)
786
- return self.create_listing(req, out_content_type, info, resp_headers,
787
- broker.metadata, container_list, container)
788
-
789
- def create_listing(self, req, out_content_type, info, resp_headers,
790
- metadata, container_list, container):
860
+ listing = [self.update_shard_record(record, shard_format_full)
861
+ for record in container_list]
862
+ return self._create_GET_response(req, out_content_type, info,
863
+ resp_headers, broker.metadata,
864
+ container, listing)
865
+
866
+ @timing_stats()
867
+ def GET_object(self, req, broker, container, params, info,
868
+ is_deleted, out_content_type):
869
+ """
870
+ Returns a list of objects in response.
871
+
872
+ :param req: swob.Request object
873
+ :param broker: container DB broker object
874
+ :param container: container name
875
+ :param params: the request params.
876
+ :param info: the global info for the container
877
+ :param is_deleted: the is_deleted status for the container.
878
+ :param out_content_type: content type as a string.
879
+ :returns: an instance of :class:`swift.common.swob.Response`
880
+ """
881
+ marker = params.get('marker', '')
882
+ end_marker = params.get('end_marker')
883
+ reverse = config_true_value(params.get('reverse'))
884
+ path = params.get('path')
885
+ prefix = params.get('prefix')
886
+ delimiter = params.get('delimiter')
887
+ limit = params['limit']
888
+ requested_policy_index = self.get_and_validate_policy_index(req)
889
+ resp_headers = gen_resp_headers(info, is_deleted=is_deleted)
890
+ if is_deleted:
891
+ return HTTPNotFound(request=req, headers=resp_headers)
892
+ resp_headers['X-Backend-Record-Type'] = 'object'
893
+ storage_policy_index = (
894
+ requested_policy_index if requested_policy_index is not None
895
+ else info['storage_policy_index'])
896
+ resp_headers['X-Backend-Record-Storage-Policy-Index'] = \
897
+ storage_policy_index
898
+ # Use the retired db while container is in process of sharding,
899
+ # otherwise use current db
900
+ src_broker = broker.get_brokers()[0]
901
+ container_list = src_broker.list_objects_iter(
902
+ limit, marker, end_marker, prefix, delimiter, path,
903
+ storage_policy_index=storage_policy_index,
904
+ reverse=reverse, allow_reserved=req.allow_reserved_names)
905
+ listing = [self.update_object_record(record)
906
+ for record in container_list]
907
+ return self._create_GET_response(req, out_content_type, info,
908
+ resp_headers, broker.metadata,
909
+ container, listing)
910
+
911
+ def _create_GET_response(self, req, out_content_type, info, resp_headers,
912
+ metadata, container, listing):
791
913
  for key, (value, _timestamp) in metadata.items():
792
914
  if value and (key.lower() in self.save_headers or
793
915
  is_sys_or_user_meta('container', key)):
794
916
  resp_headers[str_to_wsgi(key)] = str_to_wsgi(value)
795
- listing = [self.update_data_record(record)
796
- for record in container_list]
917
+
797
918
  if out_content_type.endswith('/xml'):
798
919
  body = listing_formats.container_to_xml(listing, container)
799
920
  elif out_content_type.endswith('/json'):
@@ -929,3 +1050,12 @@ def app_factory(global_conf, **local_conf):
929
1050
  conf = global_conf.copy()
930
1051
  conf.update(local_conf)
931
1052
  return ContainerController(conf)
1053
+
1054
+
1055
+ def main():
1056
+ conf_file, options = parse_options(test_config=True)
1057
+ sys.exit(run_wsgi(conf_file, 'container-server', **options))
1058
+
1059
+
1060
+ if __name__ == '__main__':
1061
+ main()