)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8546cec11914afce72883e36d9207c46e0cfa8b9","unresolved":false,"context_lines":[{"line_number":15,"context_line":"Instead, this approach entails:"},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"1.  Creating a pecan WSGI app that auto-discovers extensions written with pecan"},{"line_number":18,"context_line":"2.  Overwrides the /v3/ WSGI app\u0027s __call__ to attempt to route to the previous"},{"line_number":19,"context_line":"    WSGI implementation *first*, falling back to the pecan implementation if no"},{"line_number":20,"context_line":"    matching route is found"},{"line_number":21,"context_line":"3.  Gradually rewriting extensions using pecan.  This patchset provides an"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"AAAATn%2F85dk%3D","line":18,"updated":"2013-12-19 02:34:45.000000000","message":"typo s/Overwrides/Overrides/","commit_id":"c2512179c01ec7e624ccc33e9d5f241b341b2c6e"}],"nova/api/openstack/__init__.py":[{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"e583d83fce047debc75f5754a90421c6aef0ce6a","unresolved":false,"context_lines":[{"line_number":427,"context_line":"        controllers \u003d {}"},{"line_number":428,"context_line":"        for ext in self.api_extension_manager:"},{"line_number":429,"context_line":"            if isinstance(ext.obj, extensions.PecanV3APIExtensionBase):"},{"line_number":430,"context_line":"                controllers[ext.name] \u003d ext.obj"},{"line_number":431,"context_line":""},{"line_number":432,"context_line":"        class RootController(object):"},{"line_number":433,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F8%2Bxk%3D","line":430,"updated":"2013-12-18 05:58:49.000000000","message":"we should use \"ext.obj.alias\" as the key.","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"e583d83fce047debc75f5754a90421c6aef0ce6a","unresolved":false,"context_lines":[{"line_number":436,"context_line":"                if \u0027versions\u0027 in controllers:"},{"line_number":437,"context_line":"                    self.index \u003d controllers.pop(\u0027versions\u0027).index"},{"line_number":438,"context_line":""},{"line_number":439,"context_line":"                for name, controller in controllers:"},{"line_number":440,"context_line":"                    setattr(self, name, controller)"},{"line_number":441,"context_line":""},{"line_number":442,"context_line":"        root \u003d RootController()"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F8%2Bxs%3D","line":439,"updated":"2013-12-18 05:58:49.000000000","message":"this should \"for name, controller in controllers.items()\", otherwise you will get exception \"ValueError: need more than 1 value to unpack\"","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"e583d83fce047debc75f5754a90421c6aef0ce6a","unresolved":false,"context_lines":[{"line_number":474,"context_line":"            pass"},{"line_number":475,"context_line":""},{"line_number":476,"context_line":"        def replacement_start_response(status, headers, exc_info\u003dNone):"},{"line_number":477,"context_line":"            if status.startswith(\u00274\u0027):"},{"line_number":478,"context_line":"                # In the event of a 400-level error (meaning, a pecan"},{"line_number":479,"context_line":"                # implementation couldn\u0027t be found for the specified path),"},{"line_number":480,"context_line":"                # fall back to the previous WSGI implementation"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F8%2Bzk%3D","line":477,"updated":"2013-12-18 05:58:49.000000000","message":"it is not all the 4* that we want to fall back to old WSGI. for example, badrequest 400 raise from pecan controller, then fall back to old WSGI, old WSGi will return 404.\n\nWe can execute old WSGI first, and we change route, if there isn\u0027t any controller register on the path, we raise specific exception, then we fall back to pecan. We probably need modify at here: https://github.com/openstack/nova/blob/master/nova/wsgi.py#L455","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":5292,"name":"Christopher Yeoh","email":"cbkyeoh@gmail.com","username":"cyeoh-0"},"change_message_id":"ca33cc9040ba896975d8dc07eaef79b7090fc002","unresolved":false,"context_lines":[{"line_number":474,"context_line":"            pass"},{"line_number":475,"context_line":""},{"line_number":476,"context_line":"        def replacement_start_response(status, headers, exc_info\u003dNone):"},{"line_number":477,"context_line":"            if status.startswith(\u00274\u0027):"},{"line_number":478,"context_line":"                # In the event of a 400-level error (meaning, a pecan"},{"line_number":479,"context_line":"                # implementation couldn\u0027t be found for the specified path),"},{"line_number":480,"context_line":"                # fall back to the previous WSGI implementation"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F89%2Bc%3D","line":477,"in_reply_to":"AAAATn%2F8%2Bzk%3D","updated":"2013-12-18 09:53:54.000000000","message":"yea unless I\u0027m misunderstanding how this works we need to be able to distinguish between pecan not handling this route and a genuine 4* error code from the plugin","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":8005,"name":"Ryan Petrello","email":"ryan@ryanpetrello.com","username":"ryanpetrello"},"change_message_id":"3ef0ff26dd0fa9db3e9e029f1e0fa588e55b8519","unresolved":false,"context_lines":[{"line_number":474,"context_line":"            pass"},{"line_number":475,"context_line":""},{"line_number":476,"context_line":"        def replacement_start_response(status, headers, exc_info\u003dNone):"},{"line_number":477,"context_line":"            if status.startswith(\u00274\u0027):"},{"line_number":478,"context_line":"                # In the event of a 400-level error (meaning, a pecan"},{"line_number":479,"context_line":"                # implementation couldn\u0027t be found for the specified path),"},{"line_number":480,"context_line":"                # fall back to the previous WSGI implementation"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F88Wo%3D","line":477,"in_reply_to":"AAAATn%2F89%2Bc%3D","updated":"2013-12-18 14:51:56.000000000","message":"I think what Alex is saying here probably makes sense.  I like the idea of executing the *old* WSGI first, catching a specific \"extension not implemented\" exception, and *then* falling back to pecan.","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":6167,"name":"Ken\u0027ichi Ohmichi","email":"ken1ohmichi@gmail.com","username":"oomichi"},"change_message_id":"4e6e015008454e0bde273cbe1bc0efc5b2063663","unresolved":false,"context_lines":[{"line_number":468,"context_line":"            \u0027xmlutil\u0027: XMLUtilRenderer"},{"line_number":469,"context_line":"        })"},{"line_number":470,"context_line":""},{"line_number":471,"context_line":"    def __call__(self, environ, start_response):"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"        # First, attempt to route to the Routes-powered WSGI app"},{"line_number":474,"context_line":"        resp \u003d super(APIRouterV3, self).__call__(environ, start_response)"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2F4kQ%3D","line":471,"updated":"2014-01-07 10:24:28.000000000","message":"nit: better to move __call__ after __init__ for maintainability because I feel this __call__ is important for APIRouterV3 class.","commit_id":"18156fba88c3f1fd6055cc2d421a45b93237ef5d"}],"nova/api/openstack/compute/plugins/v3/versions.py":[{"author":{"_account_id":5292,"name":"Christopher Yeoh","email":"cbkyeoh@gmail.com","username":"cyeoh-0"},"change_message_id":"7b3ca45a0f697d796a4f8012879f2b80eaa6b8b1","unresolved":false,"context_lines":[{"line_number":26,"context_line":"    \"\"\"API Version information.\"\"\""},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"    name \u003d \"Versions\""},{"line_number":29,"context_line":"    alias \u003d \u0027versions\u0027"},{"line_number":30,"context_line":"    namespace \u003d \"http://docs.openstack.org/compute/core/versions/v3\""},{"line_number":31,"context_line":"    version \u003d 1"},{"line_number":32,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F8960%3D","line":29,"updated":"2013-12-18 09:57:50.000000000","message":"although in this case we don\u0027t need the ALIAS defined at the top as its only used in one place, I\u0027d prefer to keep all plugins looking the same.","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8546cec11914afce72883e36d9207c46e0cfa8b9","unresolved":false,"context_lines":[{"line_number":19,"context_line":"from nova.api.openstack.compute.views import versions as views_versions"},{"line_number":20,"context_line":"from nova.api.openstack import extensions"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import pecan"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"ALIAS \u003d \"versions\""},{"line_number":25,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAATn%2F85Xg%3D","line":22,"updated":"2013-12-19 02:34:45.000000000","message":"This should go before the nova imports according to pep8 iirc.","commit_id":"c2512179c01ec7e624ccc33e9d5f241b341b2c6e"}],"nova/api/openstack/extensions.py":[{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"e583d83fce047debc75f5754a90421c6aef0ce6a","unresolved":false,"context_lines":[{"line_number":473,"context_line":"        return []"},{"line_number":474,"context_line":""},{"line_number":475,"context_line":"    def get_resources(self):"},{"line_number":476,"context_line":"        return [ResourceExtension(self.alias, self)]"},{"line_number":477,"context_line":""},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"def expected_errors(errors):"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F8%2B0I%3D","line":476,"updated":"2013-12-18 05:58:49.000000000","message":"Is it enough for just return empty list?","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"},{"author":{"_account_id":8005,"name":"Ryan Petrello","email":"ryan@ryanpetrello.com","username":"ryanpetrello"},"change_message_id":"3ef0ff26dd0fa9db3e9e029f1e0fa588e55b8519","unresolved":false,"context_lines":[{"line_number":473,"context_line":"        return []"},{"line_number":474,"context_line":""},{"line_number":475,"context_line":"    def get_resources(self):"},{"line_number":476,"context_line":"        return [ResourceExtension(self.alias, self)]"},{"line_number":477,"context_line":""},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"def expected_errors(errors):"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F88Vw%3D","line":476,"in_reply_to":"AAAATn%2F8%2B0I%3D","updated":"2013-12-18 14:51:56.000000000","message":"I believe the resource discovery (which pecan uses to programmatically discover extensions implementing this class) depends on this having at least *one* resource listed here.  I\u0027ll experiment.","commit_id":"aa7a707a3bf28ef6747753a1e773e40265681fef"}]}
