)]}'
{"doc/source/read_only.rst":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":7,"context_line":"The ability to make an entire cluster or individual accounts read only is"},{"line_number":8,"context_line":"implemented as pluggable middleware.  When a cluster or an account is in read"},{"line_number":9,"context_line":"only mode, requests that would result in a writes to the cluser are not"},{"line_number":10,"context_line":"allowed.  A 503 is returned on such requests.  \"COPY\", \"POST\", and \"PUT\" are"},{"line_number":11,"context_line":"the HTTP methods that are considered writes."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"-------------"}],"source_content_type":"text/x-rst","patch_set":1,"id":"7a2fa921_9dd72b23","line":10,"updated":"2015-10-12 19:09:34.000000000","message":"why not http 405 Method Not Allowed?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":19,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":20,"context_line":"Option    Default Description"},{"line_number":21,"context_line":"--------- ------- ------------------------------------------------------"},{"line_number":22,"context_line":"read_only \u0027f\u0027     Set to \u0027t\u0027 to put the entire cluster in read only mode."},{"line_number":23,"context_line":"whitelist \u0027\u0027      A comma separated list of account names to allow to"},{"line_number":24,"context_line":"                  write. This overrides setting read only for an entire"},{"line_number":25,"context_line":"                  cluster or for individual accounts."}],"source_content_type":"text/x-rst","patch_set":1,"id":"7a2fa921_bdc30738","line":22,"updated":"2015-10-12 17:49:29.000000000","message":"Same as in the sample config: all the other boolean values are \"true\" or \"false\". It would be good to remain consistent.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fc4eaf3dbd9ee383017c4734798bffeed4530b11","unresolved":false,"context_lines":[{"line_number":32,"context_line":"If a system administrator wants to mark individual accounts as read only,"},{"line_number":33,"context_line":"he/she can set X-Account-Sysmeta-Read-Only on an account to \u0027t\u0027.  This header"},{"line_number":34,"context_line":"will be hidden from the user, because of the gatekeeper midleware, and can"},{"line_number":35,"context_line":"only be set using a direct client to the account nodes."}],"source_content_type":"text/x-rst","patch_set":1,"id":"7a2fa921_00964e94","line":35,"updated":"2015-10-12 18:13:08.000000000","message":"Is this a \"standard\" way to set sysmeta data? I seem to remember seeing other places (versioned_writes, tempauth, maybe somewhere else?) managing it through the middleware...","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":32,"context_line":"If a system administrator wants to mark individual accounts as read only,"},{"line_number":33,"context_line":"he/she can set X-Account-Sysmeta-Read-Only on an account to \u0027t\u0027.  This header"},{"line_number":34,"context_line":"will be hidden from the user, because of the gatekeeper midleware, and can"},{"line_number":35,"context_line":"only be set using a direct client to the account nodes."}],"source_content_type":"text/x-rst","patch_set":1,"id":"7a2fa921_9da5ebb6","line":35,"updated":"2015-10-12 19:09:34.000000000","message":"what takes precedence the whitelist or the sysmeta?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"61cb7b60490fea633923f65ff80fba06db7e1cca","unresolved":false,"context_lines":[{"line_number":1,"context_line":".. _read_only:"},{"line_number":2,"context_line":""},{"line_number":3,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":4,"context_line":"Read Only"},{"line_number":5,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":3,"id":"5a2ca52d_2dd901f4","line":2,"updated":"2015-10-13 21:36:27.000000000","message":"module level doc string would be *way* cooler","commit_id":"ab66769a03352c1e78ef79beb5e1e0e2cea4c946"}],"etc/proxy-server.conf-sample":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fc4eaf3dbd9ee383017c4734798bffeed4530b11","unresolved":false,"context_lines":[{"line_number":449,"context_line":"# container_listing_ratelimit_10 \u003d 50"},{"line_number":450,"context_line":"# container_listing_ratelimit_50 \u003d 20"},{"line_number":451,"context_line":""},{"line_number":452,"context_line":"[filter:read_only]"},{"line_number":453,"context_line":"use \u003d egg:swift#read_only"},{"line_number":454,"context_line":"# read_only of t means turn global read only on"},{"line_number":455,"context_line":"# read_only \u003d t"}],"source_content_type":"application/octet-stream","patch_set":1,"id":"7a2fa921_fd53bf6a","line":452,"updated":"2015-10-12 18:13:08.000000000","message":"I feel like we should include some recommendation on pipeline placement here. After auth, I\u0027d assume?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":452,"context_line":"[filter:read_only]"},{"line_number":453,"context_line":"use \u003d egg:swift#read_only"},{"line_number":454,"context_line":"# read_only of t means turn global read only on"},{"line_number":455,"context_line":"# read_only \u003d t"},{"line_number":456,"context_line":"# comma separated lists of account names to allow writes"},{"line_number":457,"context_line":"# whitelist \u003d "},{"line_number":458,"context_line":""}],"source_content_type":"application/octet-stream","patch_set":1,"id":"7a2fa921_dda9237d","line":455,"updated":"2015-10-12 17:49:29.000000000","message":"All the other boolean defaults are \"true\" or \"false\". It would be good to remain consistent here.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"41fde723a986980c3a03ae9480f247f985f9993d","unresolved":false,"context_lines":[{"line_number":449,"context_line":"# container_listing_ratelimit_10 \u003d 50"},{"line_number":450,"context_line":"# container_listing_ratelimit_50 \u003d 20"},{"line_number":451,"context_line":""},{"line_number":452,"context_line":"[filter:read_only]"},{"line_number":453,"context_line":"use \u003d egg:swift#read_only"},{"line_number":454,"context_line":"# read_only set to true means turn global read only on"},{"line_number":455,"context_line":"# read_only \u003d false"}],"source_content_type":"application/octet-stream","patch_set":4,"id":"3a29b11f_473f67b4","line":452,"updated":"2015-10-19 17:25:18.000000000","message":"I\u0027d still like some guidance on where to put this in the pipeline.","commit_id":"5505bb6907ab2b02e5138e58b61daa8d6c3e9221"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"41fde723a986980c3a03ae9480f247f985f9993d","unresolved":false,"context_lines":[{"line_number":454,"context_line":"# read_only set to true means turn global read only on"},{"line_number":455,"context_line":"# read_only \u003d false"},{"line_number":456,"context_line":"# comma separated lists of account names to allow writes"},{"line_number":457,"context_line":"# whitelist \u003d"},{"line_number":458,"context_line":"# allow_deletes \u003d false"},{"line_number":459,"context_line":""},{"line_number":460,"context_line":"[filter:domain_remap]"}],"source_content_type":"application/octet-stream","patch_set":4,"id":"3a29b11f_f16c319e","line":457,"updated":"2015-10-19 17:25:18.000000000","message":"Is this actually used anywhere? It looks like the functionality was replaced by the tri-state account sysmeta.","commit_id":"5505bb6907ab2b02e5138e58b61daa8d6c3e9221"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"af24fc7ef2377cef2f791971a29ada965ee2a404","unresolved":false,"context_lines":[{"line_number":456,"context_line":"# allow_deletes set to true means to allow deletes"},{"line_number":457,"context_line":"# allow_deletes \u003d false"},{"line_number":458,"context_line":""},{"line_number":459,"context_line":"# Note: Put before after ratelimit in the pipeline."},{"line_number":460,"context_line":"[filter:domain_remap]"},{"line_number":461,"context_line":"use \u003d egg:swift#domain_remap"},{"line_number":462,"context_line":"# You can override the default log routing for this filter here:"}],"source_content_type":"application/octet-stream","patch_set":7,"id":"3a29b11f_05040715","line":459,"updated":"2015-10-19 18:19:42.000000000","message":"before or after?","commit_id":"9cc767053c02a334ad2fdad0780aade785c57bad"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"caebb3b6c6c2cf9fee230a8953e582c40ce15ee5","unresolved":false,"context_lines":[{"line_number":456,"context_line":"# allow_deletes set to true means to allow deletes"},{"line_number":457,"context_line":"# allow_deletes \u003d false"},{"line_number":458,"context_line":""},{"line_number":459,"context_line":"# Note: Put after ratelimit in the pipeline."},{"line_number":460,"context_line":"[filter:domain_remap]"},{"line_number":461,"context_line":"use \u003d egg:swift#domain_remap"},{"line_number":462,"context_line":"# You can override the default log routing for this filter here:"}],"source_content_type":"application/octet-stream","patch_set":10,"id":"3a29b11f_91b85de7","line":459,"updated":"2015-10-26 20:30:34.000000000","message":"The spacing makes it seem like this applies to domain_remap, rather than read_only. Let\u0027s put it above the [filter:read_only] line to be consistent with staticweb, tempurl, formpost, etc.","commit_id":"a9e6a005634ab1afaf1f73a8b53dc6045da20f57"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d03403fc31f7a82e80c3b7d5e2d68c7a1b75d7cd","unresolved":false,"context_lines":[{"line_number":455,"context_line":"# read_only \u003d false"},{"line_number":456,"context_line":"# allow_deletes set to true means to allow deletes"},{"line_number":457,"context_line":"# allow_deletes \u003d false"},{"line_number":458,"context_line":"# Note: Put after ratelimit in the pipeline."},{"line_number":459,"context_line":""},{"line_number":460,"context_line":"[filter:domain_remap]"},{"line_number":461,"context_line":"use \u003d egg:swift#domain_remap"}],"source_content_type":"application/octet-stream","patch_set":11,"id":"5f7c97a3_97737b4e","line":458,"range":{"start_line":458,"start_character":12,"end_line":458,"end_character":27},"updated":"2018-05-29 19:55:51.000000000","message":"I\u0027ve got this feeling like we want it after auth -- otherwise you can check whether an account is read-only without being authorized for the account...","commit_id":"b26d6e3c54bbfd9e87ade966f4d7cb40989f4049"}],"swift/common/middleware/read_only.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":11,"context_line":"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or"},{"line_number":12,"context_line":"# implied."},{"line_number":13,"context_line":"# See the License for the specific language governing permissions and"},{"line_number":14,"context_line":"# limitations under the License."},{"line_number":15,"context_line":"from swift.common.swob import Request, Response"},{"line_number":16,"context_line":"from swift.common.utils import get_logger, config_true_value, list_from_csv"},{"line_number":17,"context_line":"from swift.proxy.controllers.base import get_account_info"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_7d87af12","line":14,"updated":"2015-10-12 19:09:34.000000000","message":"I think most of the doc.rst would look better as a module docstring here - it\u0027s a little bit easier to manage and update if we keep the doc with the code.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fc4eaf3dbd9ee383017c4734798bffeed4530b11","unresolved":false,"context_lines":[{"line_number":20,"context_line":"class ReadOnlyMiddleware(object):"},{"line_number":21,"context_line":"    def __init__(self, app, conf, logger\u003dNone):"},{"line_number":22,"context_line":"        self.app \u003d app"},{"line_number":23,"context_line":"        self.logger \u003d logger or get_logger(conf, log_route\u003d\u0027ratelimit\u0027)"},{"line_number":24,"context_line":"        self.read_only \u003d config_true_value(conf.get(\u0027read_only\u0027))"},{"line_number":25,"context_line":"        self.whitelist \u003d list_from_csv(conf.get(\u0027whitelist\u0027))"},{"line_number":26,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_5d02f370","line":23,"updated":"2015-10-12 18:13:08.000000000","message":"We should change the log_route, yeah?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fc4eaf3dbd9ee383017c4734798bffeed4530b11","unresolved":false,"context_lines":[{"line_number":27,"context_line":"    def __call__(self, env, start_response):"},{"line_number":28,"context_line":"        req \u003d Request(env)"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"        if req.method not in (\u0027COPY\u0027, \u0027POST\u0027, \u0027PUT\u0027):"},{"line_number":31,"context_line":"            return self.app(env, start_response)"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_7db56fce","line":30,"updated":"2015-10-12 18:13:08.000000000","message":"I\u0027m with John; DELETE feels like a write. What about making it a (cluster-wide) configurable?\n\nWith DELETE protection, I think this could be useful when migrating data between clusters, to ensure the old cluster never gets *any* changes.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":27,"context_line":"    def __call__(self, env, start_response):"},{"line_number":28,"context_line":"        req \u003d Request(env)"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"        if req.method not in (\u0027COPY\u0027, \u0027POST\u0027, \u0027PUT\u0027):"},{"line_number":31,"context_line":"            return self.app(env, start_response)"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_bd4d47c6","line":30,"updated":"2015-10-12 17:49:29.000000000","message":"Why no limits on DELETE? That seems like a write.\n\nAlso, with the COPY verb, the request path is only the source. The destination might be in a completely different account that\u0027s not marked read-only.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":33,"context_line":"        try:"},{"line_number":34,"context_line":"            version, account, container, obj \u003d req.split_path(1, 4, True)"},{"line_number":35,"context_line":"            if account in self.whitelist:"},{"line_number":36,"context_line":"                return self.app(env, start_response)"},{"line_number":37,"context_line":"        except ValueError:"},{"line_number":38,"context_line":"            pass"},{"line_number":39,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_9d93ab4f","line":36,"updated":"2015-10-12 19:09:34.000000000","message":"oic whitelist trumps sysmeta.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":38,"context_line":"            pass"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        if self.read_only or self.account_read_only(req):"},{"line_number":41,"context_line":"            return Response(status\u003d\u0027503 Read only\u0027,"},{"line_number":42,"context_line":"                            body\u003d\u0027The cluster is in read only mode\u0027,"},{"line_number":43,"context_line":"                            request\u003dreq)(env, start_response)"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_5d867314","line":41,"updated":"2015-10-12 19:09:34.000000000","message":"I think a HTTPMethodNotAllowed would make more sense.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":38,"context_line":"            pass"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        if self.read_only or self.account_read_only(req):"},{"line_number":41,"context_line":"            return Response(status\u003d\u0027503 Read only\u0027,"},{"line_number":42,"context_line":"                            body\u003d\u0027The cluster is in read only mode\u0027,"},{"line_number":43,"context_line":"                            request\u003dreq)(env, start_response)"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_dd736314","line":41,"updated":"2015-10-12 17:49:29.000000000","message":"This seems to redefine 503. Honestly, I\u0027m not sure about 503 or not, but if it is 503, then shouldn\u0027t it stay Service Unavailable?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        if self.read_only or self.account_read_only(req):"},{"line_number":41,"context_line":"            return Response(status\u003d\u0027503 Read only\u0027,"},{"line_number":42,"context_line":"                            body\u003d\u0027The cluster is in read only mode\u0027,"},{"line_number":43,"context_line":"                            request\u003dreq)(env, start_response)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"        return self.app(env, start_response)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_5d10b3a8","line":42,"updated":"2015-10-12 17:49:29.000000000","message":"Same message even if it\u0027s just the account that marked read-only?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        if self.read_only or self.account_read_only(req):"},{"line_number":41,"context_line":"            return Response(status\u003d\u0027503 Read only\u0027,"},{"line_number":42,"context_line":"                            body\u003d\u0027The cluster is in read only mode\u0027,"},{"line_number":43,"context_line":"                            request\u003dreq)(env, start_response)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"        return self.app(env, start_response)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_1dc79b46","line":42,"updated":"2015-10-12 19:09:34.000000000","message":"that may not be entirely true - the cluster can be read only and maybe only the account is ready only?  Does it really matter?  What\u0027s the use-case?  would the user be *surprised* by the inability to write here - or is this mainly for belts and braces on a read-only usecase like a cdn origination?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":330,"name":"John Dickinson","email":"me@not.mn","username":"notmyname"},"change_message_id":"af2eb74767ba693160902d7c322dd2aeeb8b721b","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    def account_read_only(self, req):"},{"line_number":48,"context_line":"        try:"},{"line_number":49,"context_line":"            account_info \u003d get_account_info("},{"line_number":50,"context_line":"                req.environ, self.app, swift_source\u003d\u0027RO\u0027)"},{"line_number":51,"context_line":"            return config_true_value("},{"line_number":52,"context_line":"                account_info.get(\u0027sysmeta\u0027, {}).get(\u0027read-only\u0027))"},{"line_number":53,"context_line":"        except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_bd754733","line":50,"updated":"2015-10-12 17:49:29.000000000","message":"Please add the RO value to the logs doc","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"41fde723a986980c3a03ae9480f247f985f9993d","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            account \u003d check_account_format(req, dest_account)"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"        account_read_only \u003d self.account_read_only(req, account)"},{"line_number":90,"context_line":"        if account_read_only \u003d\u003d \"off\":"},{"line_number":91,"context_line":"            return self.app(env, start_response)"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"        if self.read_only or account_read_only \u003d\u003d \"on\":"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a29b11f_07016fae","line":90,"updated":"2015-10-19 17:25:18.000000000","message":"Why hardcode it? If we consider the cluster-wide read-only status in account_read_only(), we could just use config_true_value().","commit_id":"5505bb6907ab2b02e5138e58b61daa8d6c3e9221"},{"author":{"_account_id":1009,"name":"Greg Lange","email":"greglange@gmail.com","username":"greglange"},"change_message_id":"4217b8e7c77f43091b7d46c8aa171bea75efc03a","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            account \u003d check_account_format(req, dest_account)"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"        account_read_only \u003d self.account_read_only(req, account)"},{"line_number":90,"context_line":"        if account_read_only \u003d\u003d \"off\":"},{"line_number":91,"context_line":"            return self.app(env, start_response)"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"        if self.read_only or account_read_only \u003d\u003d \"on\":"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a29b11f_ca1dbe74","line":90,"in_reply_to":"3a29b11f_07016fae","updated":"2015-10-19 17:57:41.000000000","message":"We need/have three values, On, Off, and not set, or True, False, and not set.  It\u0027s just a matter of opinion what is best.  I went with on, off, and not set.","commit_id":"5505bb6907ab2b02e5138e58b61daa8d6c3e9221"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"41fde723a986980c3a03ae9480f247f985f9993d","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        info \u003d get_info("},{"line_number":103,"context_line":"            self.app, req.environ, account, ret_not_found\u003dTrue,"},{"line_number":104,"context_line":"            swift_source\u003d\u0027RO\u0027) or {}"},{"line_number":105,"context_line":"        return info.get(\u0027sysmeta\u0027, {}).get(\u0027read-only\u0027, \u0027\u0027)"},{"line_number":106,"context_line":""},{"line_number":107,"context_line":""},{"line_number":108,"context_line":"def filter_factory(global_conf, **local_conf):"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a29b11f_67ab838a","line":105,"updated":"2015-10-19 17:25:18.000000000","message":"Why not .get(\u0027read-only\u0027, self.read_only)? If it\u0027s not present, we should default to how the cluster\u0027s configured, right?","commit_id":"5505bb6907ab2b02e5138e58b61daa8d6c3e9221"},{"author":{"_account_id":2622,"name":"Samuel Merritt","email":"spam+launchpad@andcheese.org","username":"torgomatic"},"change_message_id":"6edd5f7219a58a7e4900fed96d18827fd06c4d3f","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The ability to make an entire cluster or individual accounts read only is"},{"line_number":26,"context_line":"implemented as pluggable middleware.  When a cluster or an account is in read"},{"line_number":27,"context_line":"only mode, requests that would result in writes to the cluser are not allowed."},{"line_number":28,"context_line":"A 405 is returned on such requests.  \"COPY\", \"DELETE\", \"POST\", and"},{"line_number":29,"context_line":"\"PUT\" are the HTTP methods that are considered writes."},{"line_number":30,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"3a29b11f_b7e6c514","line":27,"updated":"2015-10-25 12:00:38.000000000","message":"nit: \"cluster\"","commit_id":"ec2fc4947d6bfca7ebcfcde189c3b6032bd294b4"},{"author":{"_account_id":2622,"name":"Samuel Merritt","email":"spam+launchpad@andcheese.org","username":"torgomatic"},"change_message_id":"6edd5f7219a58a7e4900fed96d18827fd06c4d3f","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        if not config_true_value(conf.get(\u0027allow_deletes\u0027)):"},{"line_number":72,"context_line":"            self.write_methods +\u003d [\u0027DELETE\u0027]"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def __call__(self, env, start_response):"},{"line_number":75,"context_line":"        req \u003d Request(env)"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"        if req.method not in self.write_methods:"}],"source_content_type":"text/x-python","patch_set":9,"id":"3a29b11f_d7e34104","line":74,"updated":"2015-10-25 12:00:38.000000000","message":"you could use @wsgify here and save some boilerplate. completely optional, just a thought.","commit_id":"ec2fc4947d6bfca7ebcfcde189c3b6032bd294b4"},{"author":{"_account_id":2622,"name":"Samuel Merritt","email":"spam+launchpad@andcheese.org","username":"torgomatic"},"change_message_id":"6edd5f7219a58a7e4900fed96d18827fd06c4d3f","unresolved":false,"context_lines":[{"line_number":90,"context_line":"        if account_read_only \u003d\u003d \"off\":"},{"line_number":91,"context_line":"            return self.app(env, start_response)"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"        if self.read_only or account_read_only \u003d\u003d \"on\":"},{"line_number":94,"context_line":"            return Response("},{"line_number":95,"context_line":"                status\u003d\u0027405 Method Not Allowed\u0027,"},{"line_number":96,"context_line":"                body\u003d\u0027The method is not allowed for this resource.\u0027,"}],"source_content_type":"text/x-python","patch_set":9,"id":"3a29b11f_77f02dca","line":93,"updated":"2015-10-25 12:00:38.000000000","message":"config_true_value() maybe? I know I\u0027m gonna put in \"yes\" and wonder why it\u0027s not doing anything. Not out of spite; just because I can\u0027t remember crap.","commit_id":"ec2fc4947d6bfca7ebcfcde189c3b6032bd294b4"},{"author":{"_account_id":2622,"name":"Samuel Merritt","email":"spam+launchpad@andcheese.org","username":"torgomatic"},"change_message_id":"6edd5f7219a58a7e4900fed96d18827fd06c4d3f","unresolved":false,"context_lines":[{"line_number":91,"context_line":"            return self.app(env, start_response)"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"        if self.read_only or account_read_only \u003d\u003d \"on\":"},{"line_number":94,"context_line":"            return Response("},{"line_number":95,"context_line":"                status\u003d\u0027405 Method Not Allowed\u0027,"},{"line_number":96,"context_line":"                body\u003d\u0027The method is not allowed for this resource.\u0027,"},{"line_number":97,"context_line":"                request\u003dreq)(env, start_response)"}],"source_content_type":"text/x-python","patch_set":9,"id":"3a29b11f_97edc9f1","line":94,"updated":"2015-10-25 12:00:38.000000000","message":"use swob.HTTPMethodNotAllowed and you get all this text for free","commit_id":"ec2fc4947d6bfca7ebcfcde189c3b6032bd294b4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"caebb3b6c6c2cf9fee230a8953e582c40ce15ee5","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        return self.app(env, start_response)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def account_read_only(self, req, account):"},{"line_number":99,"context_line":"        \"\"\""},{"line_number":100,"context_line":"        Returns None if X-Account-Sysmeta-Read-Only is not set."},{"line_number":101,"context_line":"        Returns True or False otherwise."}],"source_content_type":"text/x-python","patch_set":10,"id":"3a29b11f_d193354e","line":98,"updated":"2015-10-26 20:30:34.000000000","message":"I still feel like account_read_only should be answering the question \"Is this account read-only?\" instead of \"What is the state of X-Account-Sysmeta-Read-Only for this account?\"\n\nThat said, this is better to the point that I\u0027m not too worried about it.","commit_id":"a9e6a005634ab1afaf1f73a8b53dc6045da20f57"},{"author":{"_account_id":1009,"name":"Greg Lange","email":"greglange@gmail.com","username":"greglange"},"change_message_id":"ee488e644efcc41df89d9fcabc53be6fe38cd781","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        return self.app(env, start_response)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def account_read_only(self, req, account):"},{"line_number":99,"context_line":"        \"\"\""},{"line_number":100,"context_line":"        Returns None if X-Account-Sysmeta-Read-Only is not set."},{"line_number":101,"context_line":"        Returns True or False otherwise."}],"source_content_type":"text/x-python","patch_set":10,"id":"3a29b11f_6a0b4a7e","line":98,"in_reply_to":"3a29b11f_d193354e","updated":"2015-10-27 00:18:04.000000000","message":"I really think we need the three values.  True means read only the account no matter what (blacklist).  False means don\u0027t read only the account no matter what (whitelist).  Unset or set to \u0027\u0027 means do whatever is globally set.  Make sense?","commit_id":"a9e6a005634ab1afaf1f73a8b53dc6045da20f57"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d03403fc31f7a82e80c3b7d5e2d68c7a1b75d7cd","unresolved":false,"context_lines":[{"line_number":84,"context_line":""},{"line_number":85,"context_line":"        if req.method \u003d\u003d \u0027COPY\u0027 and \u0027Destination-Account\u0027 in req.headers:"},{"line_number":86,"context_line":"            dest_account \u003d req.headers.get(\u0027Destination-Account\u0027)"},{"line_number":87,"context_line":"            account \u003d check_account_format(req, dest_account)"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"        account_read_only \u003d self.account_read_only(req, account)"},{"line_number":90,"context_line":"        if account_read_only is False:"}],"source_content_type":"text/x-python","patch_set":11,"id":"5f7c97a3_17952b32","line":87,"updated":"2018-05-29 19:55:51.000000000","message":"If we put this not only after auth but after copy as well, we don\u0027t need this block.","commit_id":"b26d6e3c54bbfd9e87ade966f4d7cb40989f4049"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"2c6610965f2ecd12b0b7f35232bdcbeb41c1e072","unresolved":false,"context_lines":[{"line_number":53,"context_line":"when a cluster is in read only mode, he/she can set"},{"line_number":54,"context_line":"X-Account-Sysmeta-Read-Only on an account to \u0027false\u0027."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"This header will be hidden from the user, because of the gatekeeper midleware,"},{"line_number":57,"context_line":"and can only be set using a direct client to the account nodes."},{"line_number":58,"context_line":"\"\"\""},{"line_number":59,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_cc339daa","line":56,"range":{"start_line":56,"start_character":68,"end_line":56,"end_character":77},"updated":"2018-05-30 03:27:37.000000000","message":"middleware","commit_id":"70d40eee9010844d0717626a20fa6fb26f19c3df"}],"test/unit/common/middleware/test_read_only.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    pass"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"read_methods \u003d \u0027DELETE GET HEAD\u0027.split()"},{"line_number":34,"context_line":"write_methods \u003d \u0027COPY POST PUT\u0027.split()"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_0ecaff4f","line":33,"updated":"2015-10-12 19:09:34.000000000","message":"hrmm.. DELETE \u003d\u003d read is not super intuative","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":34,"context_line":"write_methods \u003d \u0027COPY POST PUT\u0027.split()"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"class TestRateLimit(unittest.TestCase):"},{"line_number":38,"context_line":"    def test_global_read_only_off(self):"},{"line_number":39,"context_line":"        conf \u003d {"},{"line_number":40,"context_line":"            \u0027read_only\u0027: \u0027f\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_9de16bd3","line":37,"updated":"2015-10-12 19:09:34.000000000","message":"copy/paste?","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":69,"context_line":""},{"line_number":70,"context_line":"            for method in write_methods:"},{"line_number":71,"context_line":"                req \u003d Request.blank(\u0027/v/a\u0027)"},{"line_number":72,"context_line":"                req.method \u003d method"},{"line_number":73,"context_line":"                resp \u003d ro(req.environ, start_response)"},{"line_number":74,"context_line":"                self.assertFalse(resp[0].startswith(\u0027204\u0027))"},{"line_number":75,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_1d231b07","line":72,"updated":"2015-10-12 19:09:34.000000000","message":"just use the method kwarg","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"8bf8dd4062b81f406765e0868b0e42cfe3ffa78a","unresolved":false,"context_lines":[{"line_number":113,"context_line":"                resp \u003d ro(req.environ, start_response)"},{"line_number":114,"context_line":"                self.assertTrue(resp[0].startswith(\u0027204\u0027))"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"    def test_account_read_only_on_account_whitelisted(self):"},{"line_number":117,"context_line":"        conf \u003d {"},{"line_number":118,"context_line":"            \u0027whitelist\u0027: \u0027a\u0027,"},{"line_number":119,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":1,"id":"7a2fa921_7d032f77","line":116,"updated":"2015-10-12 19:09:34.000000000","message":"even an explicit test for precedence - seems like it\u0027d be pretty sound to document the behavior.","commit_id":"f1bc8ac9b420a030aec082f063d209869edf59b4"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ba11953e66add2bb0ac43b03f80dc2eddc761d04","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        ro.logger \u003d FakeLogger()"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"        with mock.patch(\u0027swift.common.middleware.read_only.get_info\u0027,"},{"line_number":47,"context_line":"                        lambda *args, **kwargs: {}):"},{"line_number":48,"context_line":"            for method in read_methods + write_methods:"},{"line_number":49,"context_line":"                req \u003d Request.blank(\u0027/v/a\u0027)"},{"line_number":50,"context_line":"                req.method \u003d method"}],"source_content_type":"text/x-python","patch_set":8,"id":"3a29b11f_1a51a00e","line":47,"updated":"2015-10-20 10:49:32.000000000","message":"You can use mock.patch return_value to avoid using a lamda here:\n\n  with mock.patch(\u0027thing to patch\u0027, return_value\u003d{})","commit_id":"20b1eeec3d2977b66e990898d8050593ab0b012d"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ba11953e66add2bb0ac43b03f80dc2eddc761d04","unresolved":false,"context_lines":[{"line_number":60,"context_line":"        ro.logger \u003d FakeLogger()"},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"        with mock.patch(\u0027swift.common.middleware.read_only.get_info\u0027,"},{"line_number":63,"context_line":"                        lambda *args, **kwargs: {}):"},{"line_number":64,"context_line":"            for method in read_methods:"},{"line_number":65,"context_line":"                req \u003d Request.blank(\u0027/v/a\u0027)"},{"line_number":66,"context_line":"                req.method \u003d method"}],"source_content_type":"text/x-python","patch_set":8,"id":"3a29b11f_ba574c01","line":63,"updated":"2015-10-20 10:49:32.000000000","message":"return_value here too.. you get the idea.","commit_id":"20b1eeec3d2977b66e990898d8050593ab0b012d"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ba11953e66add2bb0ac43b03f80dc2eddc761d04","unresolved":false,"context_lines":[{"line_number":71,"context_line":"                req \u003d Request.blank(\u0027/v/a\u0027)"},{"line_number":72,"context_line":"                req.method \u003d method"},{"line_number":73,"context_line":"                resp \u003d ro(req.environ, start_response)"},{"line_number":74,"context_line":"                self.assertFalse(resp[0].startswith(\u0027204\u0027))"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    def test_account_read_only_on(self):"},{"line_number":77,"context_line":"        conf \u003d {}"}],"source_content_type":"text/x-python","patch_set":8,"id":"3a29b11f_da5a482a","line":74,"updated":"2015-10-20 10:49:32.000000000","message":"Shouldn\u0027t write methods with read_only \u003d true, return a 405","commit_id":"20b1eeec3d2977b66e990898d8050593ab0b012d"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ba11953e66add2bb0ac43b03f80dc2eddc761d04","unresolved":false,"context_lines":[{"line_number":94,"context_line":"                req \u003d Request.blank(\u0027/v/a\u0027)"},{"line_number":95,"context_line":"                req.method \u003d method"},{"line_number":96,"context_line":"                resp \u003d ro(req.environ, start_response)"},{"line_number":97,"context_line":"                self.assertFalse(resp[0].startswith(\u0027204\u0027))"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def test_account_read_only_off(self):"},{"line_number":100,"context_line":"        conf \u003d {}"}],"source_content_type":"text/x-python","patch_set":8,"id":"3a29b11f_7a421440","line":97,"updated":"2015-10-20 10:49:32.000000000","message":"Shouldn\u0027t this return a 405 too?","commit_id":"20b1eeec3d2977b66e990898d8050593ab0b012d"}]}
