)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":16,"context_line":"image state is unchanged."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Change-Id: Id3ac19488c0a693d7042be4a3c83f3b9f12313d0"},{"line_number":19,"context_line":"Implements: import-multi-stores"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":24,"id":"3fa7e38b_cfd2c7cf","line":19,"range":{"start_line":19,"start_character":12,"end_line":19,"end_character":31},"updated":"2020-02-10 05:28:36.000000000","message":"change it to\nblueprint import-multi-stores","commit_id":"8b7610ca1fa4de504c5115b1f8177cdc0d6007ac"}],"glance/api/v2/image_data.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"086ced12b4cf62e8e525ff2727a7795e2bf6da62","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    def upload(self, req, image_id, data, size):"},{"line_number":123,"context_line":"        backend \u003d None"},{"line_number":124,"context_line":"        if CONF.enabled_backends:"},{"line_number":125,"context_line":"            backend \u003d [req.headers.get(\u0027x-image-meta-store\u0027,"},{"line_number":126,"context_line":"                                       CONF.glance_store.default_backend)]"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"            try:"},{"line_number":129,"context_line":"                glance_store.get_store_from_store_identifier(backend[0])"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_5d64b121","line":126,"range":{"start_line":125,"start_character":22,"end_line":126,"end_character":74},"updated":"2019-11-29 05:28:14.000000000","message":"why wrapping it in list and passing 0th index below?","commit_id":"71535810973f82d2b5cb34474b483588e57d3fcb"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"0d5c11b14cf9bf4c4c953a545706070ae14c4181","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    def upload(self, req, image_id, data, size):"},{"line_number":123,"context_line":"        backend \u003d None"},{"line_number":124,"context_line":"        if CONF.enabled_backends:"},{"line_number":125,"context_line":"            backend \u003d [req.headers.get(\u0027x-image-meta-store\u0027,"},{"line_number":126,"context_line":"                                       CONF.glance_store.default_backend)]"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"            try:"},{"line_number":129,"context_line":"                glance_store.get_store_from_store_identifier(backend[0])"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_a35ca619","line":126,"range":{"start_line":125,"start_character":22,"end_line":126,"end_character":74},"in_reply_to":"3fa7e38b_5d64b121","updated":"2019-11-29 08:34:44.000000000","message":"Since set_data method now take a list of stores as backend parameter, I have to wrap this one backend to a list. Either this or I add a line \u0027backend \u003d [backend]\u0027 on l134","commit_id":"71535810973f82d2b5cb34474b483588e57d3fcb"}],"glance/api/v2/images.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"67bff7cb858bce87ef325f632f1d761660cc9baf","unresolved":false,"context_lines":[{"line_number":105,"context_line":"        task_repo \u003d self.gateway.get_task_repo(req.context)"},{"line_number":106,"context_line":"        import_method \u003d body.get(\u0027method\u0027).get(\u0027name\u0027)"},{"line_number":107,"context_line":"        uri \u003d body.get(\u0027method\u0027).get(\u0027uri\u0027)"},{"line_number":108,"context_line":"        allow_failure \u003d body.get(\u0027method\u0027).get(\u0027allow_failure\u0027)"},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"        try:"},{"line_number":111,"context_line":"            image \u003d image_repo.get(image_id)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_32ff7e67","line":108,"range":{"start_line":108,"start_character":8,"end_line":108,"end_character":63},"updated":"2019-12-03 05:58:46.000000000","message":"https://review.opendev.org/#/c/669201/14/specs/ussuri/approved/glance/import-multi-stores.rst@165\n\nIn specs allow_failure is new body parameter, but here you are accessing it as a part of existing parameter, I guess this is for testing purpose only or you need to keep this in mind to correct this.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"b8d962c9b7d842337bd3ba005c44364067c7cdf6","unresolved":false,"context_lines":[{"line_number":105,"context_line":"        task_repo \u003d self.gateway.get_task_repo(req.context)"},{"line_number":106,"context_line":"        import_method \u003d body.get(\u0027method\u0027).get(\u0027name\u0027)"},{"line_number":107,"context_line":"        uri \u003d body.get(\u0027method\u0027).get(\u0027uri\u0027)"},{"line_number":108,"context_line":"        allow_failure \u003d body.get(\u0027method\u0027).get(\u0027allow_failure\u0027)"},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"        try:"},{"line_number":111,"context_line":"            image \u003d image_repo.get(image_id)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_3ba196f8","line":108,"range":{"start_line":108,"start_character":8,"end_line":108,"end_character":63},"in_reply_to":"3fa7e38b_32ff7e67","updated":"2019-12-03 13:32:06.000000000","message":"Bad copy/paste, thanks.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":5314,"name":"Brian Rosmaita","email":"rosmaita.fossdev@gmail.com","username":"brian-rosmaita"},"change_message_id":"f370b93286b8d6f0d5902e919080e2778d617eb4","unresolved":false,"context_lines":[{"line_number":141,"context_line":"            raise webob.exc.HTTPNotFound(explanation\u003de.msg)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        if allow_failure and not CONF.enabled_backends:"},{"line_number":144,"context_line":"            msg \u003d (_(\"Allow_failure can only bet set with enabled_backends %s\")"},{"line_number":145,"context_line":"                   % uri)"},{"line_number":146,"context_line":"            raise webob.exc.HTTPBadRequest(explanation\u003dmsg)"},{"line_number":147,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"3fa7e38b_478f30d3","line":144,"range":{"start_line":144,"start_character":45,"end_line":144,"end_character":48},"updated":"2019-12-13 21:56:30.000000000","message":"typo","commit_id":"f1129c8f42e47a8552cfd43bd50729a63012eb4c"}],"glance/async_/flows/api_image_import.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"944157966db306638367169d7c6d9e94f15b9a15","unresolved":false,"context_lines":[{"line_number":265,"context_line":""},{"line_number":266,"context_line":"    def revert(self, result, **kwargs):"},{"line_number":267,"context_line":"        \"\"\""},{"line_number":268,"context_line":"        Remove location from image in case of failure"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        :param result: taskflow result object"},{"line_number":271,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_32aa1e84","line":268,"range":{"start_line":268,"start_character":8,"end_line":268,"end_character":53},"updated":"2019-12-03 05:36:00.000000000","message":"What about removing the data from the location, you are just removing location entry, I guess data will remain there forever.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"82b73a0739e1bf2b6313a3c827c43967aa5973c4","unresolved":false,"context_lines":[{"line_number":265,"context_line":""},{"line_number":266,"context_line":"    def revert(self, result, **kwargs):"},{"line_number":267,"context_line":"        \"\"\""},{"line_number":268,"context_line":"        Remove location from image in case of failure"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        :param result: taskflow result object"},{"line_number":271,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_ffb2ff05","line":268,"range":{"start_line":268,"start_character":8,"end_line":268,"end_character":53},"in_reply_to":"3fa7e38b_1f703ba4","updated":"2019-12-03 21:57:59.000000000","message":"In the specs, we said that we want to set the image to active only when all stores have been treated. Unfortunately the logic you applied will set the image to \u0027active\u0027 after the first upload. I didn\u0027t find a simpler way than adding a new parameter \u0027set_active\u0027 :/","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"b8d962c9b7d842337bd3ba005c44364067c7cdf6","unresolved":false,"context_lines":[{"line_number":265,"context_line":""},{"line_number":266,"context_line":"    def revert(self, result, **kwargs):"},{"line_number":267,"context_line":"        \"\"\""},{"line_number":268,"context_line":"        Remove location from image in case of failure"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        :param result: taskflow result object"},{"line_number":271,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_3b0bd6d5","line":268,"range":{"start_line":268,"start_character":8,"end_line":268,"end_character":53},"in_reply_to":"3fa7e38b_32aa1e84","updated":"2019-12-03 13:32:06.000000000","message":"I used the same method as in _do_remove_locations in api/v2/images.py@l603.\nFrom my understanding, pop calls pop from StoreLocations (glance/location.py@l240) which delete data from store.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"af44664c32e7bb3b5fcd7c00aefe360966dd21f2","unresolved":false,"context_lines":[{"line_number":265,"context_line":""},{"line_number":266,"context_line":"    def revert(self, result, **kwargs):"},{"line_number":267,"context_line":"        \"\"\""},{"line_number":268,"context_line":"        Remove location from image in case of failure"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        :param result: taskflow result object"},{"line_number":271,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_1f703ba4","line":268,"range":{"start_line":268,"start_character":8,"end_line":268,"end_character":53},"in_reply_to":"3fa7e38b_3b0bd6d5","updated":"2019-12-03 21:40:26.000000000","message":"Also, if you see set_data in location.py, i have applied simple logic on setting image active in my patch so that we don’t need to pass additional flag all the layers down there. (If you find it convenient otherwise no other way than passing the flag)","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"944157966db306638367169d7c6d9e94f15b9a15","unresolved":false,"context_lines":[{"line_number":374,"context_line":"    import_method \u003d kwargs.get(\u0027import_req\u0027)[\u0027method\u0027][\u0027name\u0027]"},{"line_number":375,"context_line":"    uri \u003d kwargs.get(\u0027import_req\u0027)[\u0027method\u0027].get(\u0027uri\u0027)"},{"line_number":376,"context_line":"    stores \u003d kwargs.get(\u0027backend\u0027, [None])"},{"line_number":377,"context_line":"    allow_failure \u003d kwargs.get(\u0027import_req\u0027).get(\u0027allow_failure\u0027, False)"},{"line_number":378,"context_line":""},{"line_number":379,"context_line":"    separator \u003d \u0027\u0027"},{"line_number":380,"context_line":"    if not CONF.enabled_backends and not CONF.node_staging_uri.endswith(\u0027/\u0027):"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_529d5a6a","line":377,"range":{"start_line":377,"start_character":4,"end_line":377,"end_character":72},"updated":"2019-12-03 05:36:00.000000000","message":"Here, https://review.opendev.org/#/c/667132/8/glance/api/v2/images.py@108 you are getting allow_failure as;\n\nallow_failure \u003d body.get(\u0027method\u0027).get(\u0027allow_failure\u0027)\n\nSo at line 377 you will get allow_failure False always unless you change it to\n\nallow_failure \u003d kwargs.get(\u0027import_req\u0027)[\u0027method\u0027].get(\u0027allow_failure\u0027, False)","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"b8d962c9b7d842337bd3ba005c44364067c7cdf6","unresolved":false,"context_lines":[{"line_number":374,"context_line":"    import_method \u003d kwargs.get(\u0027import_req\u0027)[\u0027method\u0027][\u0027name\u0027]"},{"line_number":375,"context_line":"    uri \u003d kwargs.get(\u0027import_req\u0027)[\u0027method\u0027].get(\u0027uri\u0027)"},{"line_number":376,"context_line":"    stores \u003d kwargs.get(\u0027backend\u0027, [None])"},{"line_number":377,"context_line":"    allow_failure \u003d kwargs.get(\u0027import_req\u0027).get(\u0027allow_failure\u0027, False)"},{"line_number":378,"context_line":""},{"line_number":379,"context_line":"    separator \u003d \u0027\u0027"},{"line_number":380,"context_line":"    if not CONF.enabled_backends and not CONF.node_staging_uri.endswith(\u0027/\u0027):"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_5b6fb2c3","line":377,"range":{"start_line":377,"start_character":4,"end_line":377,"end_character":72},"in_reply_to":"3fa7e38b_529d5a6a","updated":"2019-12-03 13:32:06.000000000","message":"Bad copy/paste in images.py@108, should be:\nallow_failure \u003d body.get(\u0027allow_failure\u0027, False)","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"1a936270f2e70caf70d88fd7c77b71de822bd8dd","unresolved":false,"context_lines":[{"line_number":405,"context_line":"    for plugin in import_plugins.get_import_plugins(**kwargs):"},{"line_number":406,"context_line":"        flow.add(plugin)"},{"line_number":407,"context_line":""},{"line_number":408,"context_line":"    import_task \u003d lf.Flow(task_type)"},{"line_number":409,"context_line":"    for store in stores:"},{"line_number":410,"context_line":"        import_to_store \u003d _ImportToStore(task_id,"},{"line_number":411,"context_line":"                                         task_type,"},{"line_number":412,"context_line":"                                         image_repo,"},{"line_number":413,"context_line":"                                         file_uri,"},{"line_number":414,"context_line":"                                         image_id,"},{"line_number":415,"context_line":"                                         store,"},{"line_number":416,"context_line":"                                         allow_failure)"},{"line_number":417,"context_line":"        import_task.add(import_to_store)"},{"line_number":418,"context_line":"    flow.add(import_task)"},{"line_number":419,"context_line":""},{"line_number":420,"context_line":"    delete_task \u003d lf.Flow(task_type).add(_DeleteFromFS(task_id, task_type))"},{"line_number":421,"context_line":"    flow.add(delete_task)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_8de2d72f","line":418,"range":{"start_line":408,"start_character":4,"end_line":418,"end_character":25},"updated":"2019-12-03 21:20:34.000000000","message":"This is raising error;\n\nTaskflow executor picked up the execution of task ID 54d2cf4a-f3c2-418c-af10-929c41639f96 of task type api_image_import {{(pid\u003d21507) _run /opt/stack/glance/glance/async_/taskflow_executor.py:157}}\nDec 03 07:18:55 train glance-api[21473]: ERROR glance.async_.taskflow_executor [-] Failed to execute task 54d2cf4a-f3c2-418c-af10-929c41639f96: Atoms with duplicate names found: [\u0027api_image_import-ImportToStore-54d2cf4a-f3c2-418c-af10-929c41639f96\u0027]: taskflow.exceptions.Duplicate: Atoms with duplicate names found: [\u0027api_image_import-ImportToStore-54d2cf4a-f3c2-418c-af10-929c41639f96\u0027]","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"d33c73be23931aa13790b2fef4db216a3725f2a4","unresolved":false,"context_lines":[{"line_number":405,"context_line":"    for plugin in import_plugins.get_import_plugins(**kwargs):"},{"line_number":406,"context_line":"        flow.add(plugin)"},{"line_number":407,"context_line":""},{"line_number":408,"context_line":"    import_task \u003d lf.Flow(task_type)"},{"line_number":409,"context_line":"    for store in stores:"},{"line_number":410,"context_line":"        import_to_store \u003d _ImportToStore(task_id,"},{"line_number":411,"context_line":"                                         task_type,"},{"line_number":412,"context_line":"                                         image_repo,"},{"line_number":413,"context_line":"                                         file_uri,"},{"line_number":414,"context_line":"                                         image_id,"},{"line_number":415,"context_line":"                                         store,"},{"line_number":416,"context_line":"                                         allow_failure)"},{"line_number":417,"context_line":"        import_task.add(import_to_store)"},{"line_number":418,"context_line":"    flow.add(import_task)"},{"line_number":419,"context_line":""},{"line_number":420,"context_line":"    delete_task \u003d lf.Flow(task_type).add(_DeleteFromFS(task_id, task_type))"},{"line_number":421,"context_line":"    flow.add(delete_task)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_3f25f7ae","line":418,"range":{"start_line":408,"start_character":4,"end_line":418,"end_character":25},"in_reply_to":"3fa7e38b_8de2d72f","updated":"2019-12-03 21:33:56.000000000","message":"Thanks, I\u0027ll upload a new patch with your fix.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"1a936270f2e70caf70d88fd7c77b71de822bd8dd","unresolved":false,"context_lines":[{"line_number":416,"context_line":"                                         allow_failure)"},{"line_number":417,"context_line":"        import_task.add(import_to_store)"},{"line_number":418,"context_line":"    flow.add(import_task)"},{"line_number":419,"context_line":""},{"line_number":420,"context_line":"    delete_task \u003d lf.Flow(task_type).add(_DeleteFromFS(task_id, task_type))"},{"line_number":421,"context_line":"    flow.add(delete_task)"},{"line_number":422,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_2de9637e","line":419,"updated":"2019-12-03 21:20:34.000000000","message":"In my copy patch, I have modified this code where this error is not raised and working as expected.","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"1587184250451e3d5887ef9f9ded41eb5f83dcfb","unresolved":false,"context_lines":[{"line_number":271,"context_line":""},{"line_number":272,"context_line":"        :param result: taskflow result object"},{"line_number":273,"context_line":"        \"\"\""},{"line_number":274,"context_line":"        image \u003d self.image_repo.get(self.image_id)"},{"line_number":275,"context_line":"        for i, location in enumerate(image.locations):"},{"line_number":276,"context_line":"            if location.get(\u0027metadata\u0027, {}).get(\u0027store\u0027) \u003d\u003d self.backend:"},{"line_number":277,"context_line":"                try:"},{"line_number":278,"context_line":"                    image.locations.pop(i)"},{"line_number":279,"context_line":"                except (store_exceptions.NotFound,"},{"line_number":280,"context_line":"                        store_exceptions.Forbidden):"},{"line_number":281,"context_line":"                    msg \u003d (_(\"Error deleting from store %{store}s when \""},{"line_number":282,"context_line":"                             \"reverting.\") % {\u0027store\u0027: self.backend})"},{"line_number":283,"context_line":"                    LOG.warning(msg)"},{"line_number":284,"context_line":"                # NOTE(yebinama): Some store drivers doesn\u0027t document which"},{"line_number":285,"context_line":"                # exceptions they throw."},{"line_number":286,"context_line":"                except Exception:"},{"line_number":287,"context_line":"                    msg \u003d (_(\"Unexpected exception when deleting from store\""},{"line_number":288,"context_line":"                             \"%{store}s.\") % {\u0027store\u0027: self.backend})"},{"line_number":289,"context_line":"                    LOG.warning(msg)"},{"line_number":290,"context_line":"                else:"},{"line_number":291,"context_line":"                    self.image_repo.save(image)"},{"line_number":292,"context_line":"                break"},{"line_number":293,"context_line":""},{"line_number":294,"context_line":""},{"line_number":295,"context_line":"class _SaveImage(task.Task):"}],"source_content_type":"text/x-python","patch_set":12,"id":"3fa7e38b_6ceac1d9","line":292,"range":{"start_line":274,"start_character":8,"end_line":292,"end_character":21},"updated":"2019-12-13 06:51:48.000000000","message":"Even this revert method is removing and clearing the data from existing locations, data is still in staging area and image status remains \u0027importing\u0027. \n\nIMO image status should also be reverted back to \u0027uploading\u0027 so that user can issue import command again after analyzing the failure cause. Otherwise there is no use of this image and the data in staging will remain there even after image is deleted.","commit_id":"7a8b9b70229a5151a60a7ce6ce85e772efb6872c"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"f98c77a6ab910f719d648be5dc1eec75c5795d08","unresolved":false,"context_lines":[{"line_number":271,"context_line":""},{"line_number":272,"context_line":"        :param result: taskflow result object"},{"line_number":273,"context_line":"        \"\"\""},{"line_number":274,"context_line":"        image \u003d self.image_repo.get(self.image_id)"},{"line_number":275,"context_line":"        for i, location in enumerate(image.locations):"},{"line_number":276,"context_line":"            if location.get(\u0027metadata\u0027, {}).get(\u0027store\u0027) \u003d\u003d self.backend:"},{"line_number":277,"context_line":"                try:"},{"line_number":278,"context_line":"                    image.locations.pop(i)"},{"line_number":279,"context_line":"                except (store_exceptions.NotFound,"},{"line_number":280,"context_line":"                        store_exceptions.Forbidden):"},{"line_number":281,"context_line":"                    msg \u003d (_(\"Error deleting from store %{store}s when \""},{"line_number":282,"context_line":"                             \"reverting.\") % {\u0027store\u0027: self.backend})"},{"line_number":283,"context_line":"                    LOG.warning(msg)"},{"line_number":284,"context_line":"                # NOTE(yebinama): Some store drivers doesn\u0027t document which"},{"line_number":285,"context_line":"                # exceptions they throw."},{"line_number":286,"context_line":"                except Exception:"},{"line_number":287,"context_line":"                    msg \u003d (_(\"Unexpected exception when deleting from store\""},{"line_number":288,"context_line":"                             \"%{store}s.\") % {\u0027store\u0027: self.backend})"},{"line_number":289,"context_line":"                    LOG.warning(msg)"},{"line_number":290,"context_line":"                else:"},{"line_number":291,"context_line":"                    self.image_repo.save(image)"},{"line_number":292,"context_line":"                break"},{"line_number":293,"context_line":""},{"line_number":294,"context_line":""},{"line_number":295,"context_line":"class _SaveImage(task.Task):"}],"source_content_type":"text/x-python","patch_set":12,"id":"3fa7e38b_a4fe2204","line":292,"range":{"start_line":274,"start_character":8,"end_line":292,"end_character":21},"in_reply_to":"3fa7e38b_6ceac1d9","updated":"2019-12-13 20:57:58.000000000","message":"Erno Kuvaja asked in the specs to only delete the image from the store, not from staging area.\nFor the status, we have to keep the original status to go back to it. For example, when using this flow with the method \"copy-image\" the revert should let the image to \"ACTIVE\". I\u0027ll think on how to handle that.","commit_id":"7a8b9b70229a5151a60a7ce6ce85e772efb6872c"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"1587184250451e3d5887ef9f9ded41eb5f83dcfb","unresolved":false,"context_lines":[{"line_number":28,"context_line":"import glance.async_.flows._internal_plugins as internal_plugins"},{"line_number":29,"context_line":"import glance.async_.flows.plugins as import_plugins"},{"line_number":30,"context_line":"from glance.common import exception"},{"line_number":31,"context_line":"from glance.common.exception import ImportTaskError"},{"line_number":32,"context_line":"from glance.common.scripts.image_import import main as image_import"},{"line_number":33,"context_line":"from glance.common.scripts import utils as script_utils"},{"line_number":34,"context_line":"from glance.i18n import _, _LE, _LI"}],"source_content_type":"text/x-python","patch_set":13,"id":"3fa7e38b_32db854e","line":31,"range":{"start_line":31,"start_character":0,"end_line":31,"end_character":51},"updated":"2019-12-13 06:51:48.000000000","message":"This is against OpenStack standards.\nyou can use exception.ImportTaskError","commit_id":"6b797ba47b13949064c046eb04f260d5799aaedb"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"f98c77a6ab910f719d648be5dc1eec75c5795d08","unresolved":false,"context_lines":[{"line_number":28,"context_line":"import glance.async_.flows._internal_plugins as internal_plugins"},{"line_number":29,"context_line":"import glance.async_.flows.plugins as import_plugins"},{"line_number":30,"context_line":"from glance.common import exception"},{"line_number":31,"context_line":"from glance.common.exception import ImportTaskError"},{"line_number":32,"context_line":"from glance.common.scripts.image_import import main as image_import"},{"line_number":33,"context_line":"from glance.common.scripts import utils as script_utils"},{"line_number":34,"context_line":"from glance.i18n import _, _LE, _LI"}],"source_content_type":"text/x-python","patch_set":13,"id":"3fa7e38b_44eace77","line":31,"range":{"start_line":31,"start_character":0,"end_line":31,"end_character":51},"in_reply_to":"3fa7e38b_32db854e","updated":"2019-12-13 20:57:58.000000000","message":"I\u0027ll fix it in next patch.","commit_id":"6b797ba47b13949064c046eb04f260d5799aaedb"},{"author":{"_account_id":5202,"name":"Erno Kuvaja","email":"jokke@usr.fi","username":"jokke"},"change_message_id":"cb2144a7cfdab73f6b09459ce781a63e64cc5008","unresolved":false,"context_lines":[{"line_number":270,"context_line":"                    \u0027os_glance_failed_import\u0027, \u0027\u0027).split()"},{"line_number":271,"context_line":"                failed_import.append(self.backend)"},{"line_number":272,"context_line":"                image.extra_properties["},{"line_number":273,"context_line":"                    \u0027os_glance_failed_import\u0027] \u003d \u0027 \u0027.join(failed_import)"},{"line_number":274,"context_line":"        if self.backend is not None:"},{"line_number":275,"context_line":"            importing \u003d image.extra_properties.get("},{"line_number":276,"context_line":"                \u0027os_glance_importing_to_stores\u0027, \u0027\u0027).split()"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_6ec27988","line":273,"range":{"start_line":273,"start_character":49,"end_line":273,"end_character":72},"updated":"2020-01-27 13:30:37.000000000","message":"I think we have nothing preventing having whitespaces in the StoreID, probably should populate these as comma separated values. (please don\u0027t forget the .split(\u0027,\u0027)s","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"aca7c09d18f9d7257a02e4c668d327ffe290c60d","unresolved":false,"context_lines":[{"line_number":270,"context_line":"                    \u0027os_glance_failed_import\u0027, \u0027\u0027).split()"},{"line_number":271,"context_line":"                failed_import.append(self.backend)"},{"line_number":272,"context_line":"                image.extra_properties["},{"line_number":273,"context_line":"                    \u0027os_glance_failed_import\u0027] \u003d \u0027 \u0027.join(failed_import)"},{"line_number":274,"context_line":"        if self.backend is not None:"},{"line_number":275,"context_line":"            importing \u003d image.extra_properties.get("},{"line_number":276,"context_line":"                \u0027os_glance_importing_to_stores\u0027, \u0027\u0027).split()"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_48868db9","line":273,"range":{"start_line":273,"start_character":49,"end_line":273,"end_character":72},"in_reply_to":"3fa7e38b_6ec27988","updated":"2020-01-27 20:48:41.000000000","message":"Ok I\u0027ll update this","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":5202,"name":"Erno Kuvaja","email":"jokke@usr.fi","username":"jokke"},"change_message_id":"cb2144a7cfdab73f6b09459ce781a63e64cc5008","unresolved":false,"context_lines":[{"line_number":277,"context_line":"            try:"},{"line_number":278,"context_line":"                importing.remove(self.backend)"},{"line_number":279,"context_line":"                image.extra_properties["},{"line_number":280,"context_line":"                    \u0027os_glance_importing_to_stores\u0027] \u003d \u0027 \u0027.join(importing)"},{"line_number":281,"context_line":"            except ValueError:"},{"line_number":282,"context_line":"                LOG.debug(\"Store %s not found in property \""},{"line_number":283,"context_line":"                          \"os_glance_importing_to_stores.\", self.backend)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_2eb80110","line":280,"range":{"start_line":280,"start_character":55,"end_line":280,"end_character":74},"updated":"2020-01-27 13:30:37.000000000","message":"Ditto","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":5202,"name":"Erno Kuvaja","email":"jokke@usr.fi","username":"jokke"},"change_message_id":"cb2144a7cfdab73f6b09459ce781a63e64cc5008","unresolved":false,"context_lines":[{"line_number":463,"context_line":"    from_state \u003d image.status"},{"line_number":464,"context_line":"    image.status \u003d \u0027importing\u0027"},{"line_number":465,"context_line":"    image.extra_properties["},{"line_number":466,"context_line":"        \u0027os_glance_importing_to_stores\u0027] \u003d \u0027 \u0027.join((store for store in"},{"line_number":467,"context_line":"                                                     stores if"},{"line_number":468,"context_line":"                                                     store is not None))"},{"line_number":469,"context_line":"    image.extra_properties[\u0027os_glance_failed_import\u0027] \u003d \u0027\u0027"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_ee33c9c2","line":466,"range":{"start_line":466,"start_character":43,"end_line":466,"end_character":52},"updated":"2020-01-27 13:30:37.000000000","message":"Ditto","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":292,"context_line":""},{"line_number":293,"context_line":"        :param result: taskflow result object"},{"line_number":294,"context_line":"        \"\"\""},{"line_number":295,"context_line":"        image \u003d self.image_repo.get(self.image_id)"},{"line_number":296,"context_line":"        for i, location in enumerate(image.locations):"},{"line_number":297,"context_line":"            if location.get(\u0027metadata\u0027, {}).get(\u0027store\u0027) \u003d\u003d self.backend:"},{"line_number":298,"context_line":"                try:"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_0fe69fb0","line":295,"range":{"start_line":295,"start_character":8,"end_line":295,"end_character":50},"updated":"2020-02-10 05:28:36.000000000","message":"While reverting as well should we also check if image is deleted or not?","commit_id":"8b7610ca1fa4de504c5115b1f8177cdc0d6007ac"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"7fd4d96f987b6cc96497171027f87c9c42bff238","unresolved":false,"context_lines":[{"line_number":292,"context_line":""},{"line_number":293,"context_line":"        :param result: taskflow result object"},{"line_number":294,"context_line":"        \"\"\""},{"line_number":295,"context_line":"        image \u003d self.image_repo.get(self.image_id)"},{"line_number":296,"context_line":"        for i, location in enumerate(image.locations):"},{"line_number":297,"context_line":"            if location.get(\u0027metadata\u0027, {}).get(\u0027store\u0027) \u003d\u003d self.backend:"},{"line_number":298,"context_line":"                try:"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_953b7cc7","line":295,"range":{"start_line":295,"start_character":8,"end_line":295,"end_character":50},"in_reply_to":"3fa7e38b_0fe69fb0","updated":"2020-02-10 08:42:57.000000000","message":"If image is deleted, the locations should be empty and we shouldn\u0027t enter the loop. Hence I think we don\u0027t need to check the status here.","commit_id":"8b7610ca1fa4de504c5115b1f8177cdc0d6007ac"}],"glance/common/utils.py":[{"author":{"_account_id":5202,"name":"Erno Kuvaja","email":"jokke@usr.fi","username":"jokke"},"change_message_id":"60f14e2f04b151cfb6ca9a6a374bd81ba680a82b","unresolved":false,"context_lines":[{"line_number":729,"context_line":"    raise exception.InvalidFilterOperatorValue(msg)"},{"line_number":730,"context_line":""},{"line_number":731,"context_line":""},{"line_number":732,"context_line":"def get_stores_from_request(req, body):"},{"line_number":733,"context_line":"    \"\"\"Processes a supplied request and extract stores from it"},{"line_number":734,"context_line":""},{"line_number":735,"context_line":"    :param req: request to process"},{"line_number":736,"context_line":"    :param body: request body"},{"line_number":737,"context_line":""},{"line_number":738,"context_line":"    :raises glance_store.UnknownScheme:  if a store is not valid"},{"line_number":739,"context_line":"    :return: a list of stores"},{"line_number":740,"context_line":"    \"\"\""},{"line_number":741,"context_line":"    try:"},{"line_number":742,"context_line":"        stores \u003d body[\u0027stores\u0027]"},{"line_number":743,"context_line":"    except KeyError:"},{"line_number":744,"context_line":"        stores \u003d [req.headers.get(\u0027x-image-meta-store\u0027,"},{"line_number":745,"context_line":"                                  CONF.glance_store.default_backend)]"},{"line_number":746,"context_line":"    else:"},{"line_number":747,"context_line":"        if \u0027x-image-meta-store\u0027 in req.headers:"},{"line_number":748,"context_line":"            msg \u003d _(\"Stores parameter and x-image-meta-store header can\u0027t \""},{"line_number":749,"context_line":"                    \"be both specified\")"},{"line_number":750,"context_line":"            raise exc.HTTPBadRequest(explanation\u003dmsg)"},{"line_number":751,"context_line":"    # Validate each store"},{"line_number":752,"context_line":"    for store in stores:"},{"line_number":753,"context_line":"        glance_store.get_store_from_store_identifier(store)"},{"line_number":754,"context_line":"    return stores"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_6c8213ca","line":754,"range":{"start_line":732,"start_character":0,"end_line":754,"end_character":17},"updated":"2019-12-01 12:37:51.000000000","message":"This looks great!","commit_id":"71535810973f82d2b5cb34474b483588e57d3fcb"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"caa6af437b7fa79f790ae880cfb989e80e5d7580","unresolved":false,"context_lines":[{"line_number":739,"context_line":"    :return: a list of stores"},{"line_number":740,"context_line":"    \"\"\""},{"line_number":741,"context_line":"    try:"},{"line_number":742,"context_line":"        stores \u003d body[\u0027stores\u0027]"},{"line_number":743,"context_line":"    except KeyError:"},{"line_number":744,"context_line":"        stores \u003d [req.headers.get(\u0027x-image-meta-store\u0027,"},{"line_number":745,"context_line":"                                  CONF.glance_store.default_backend)]"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_ad88f36a","line":742,"range":{"start_line":742,"start_character":16,"end_line":742,"end_character":31},"updated":"2019-12-03 07:17:00.000000000","message":"passing stores in body raising\n \u003ch1\u003e400 Bad Request\u003c/h1\u003e\n  Malformed JSON in request body.\u003cbr /\u003e\u003cbr /\u003e\n\nRequest url:\ncurl -g -i -X POST http://controller-ip/v2/images/d7d6a80b-8dbfeb9-95bcb85647af/import -H \"User-Agent: python-glanceclient\" -H \"Content-Type: application/json\" -H \"X-Auth-Token: auth-token\" -d \u0027{\"method\": {\"name\": \"copy-image\"} \"stores\": [\"fast\", \"cheap\"]}\u0027","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"b8d962c9b7d842337bd3ba005c44364067c7cdf6","unresolved":false,"context_lines":[{"line_number":739,"context_line":"    :return: a list of stores"},{"line_number":740,"context_line":"    \"\"\""},{"line_number":741,"context_line":"    try:"},{"line_number":742,"context_line":"        stores \u003d body[\u0027stores\u0027]"},{"line_number":743,"context_line":"    except KeyError:"},{"line_number":744,"context_line":"        stores \u003d [req.headers.get(\u0027x-image-meta-store\u0027,"},{"line_number":745,"context_line":"                                  CONF.glance_store.default_backend)]"}],"source_content_type":"text/x-python","patch_set":8,"id":"3fa7e38b_db12c2fd","line":742,"range":{"start_line":742,"start_character":16,"end_line":742,"end_character":31},"in_reply_to":"3fa7e38b_ad88f36a","updated":"2019-12-03 13:32:06.000000000","message":"I think you just forgot to add a comma between \u0027method\u0027 and \u0027stores\u0027 in your json.\n \u0027{\"method\": {\"name\": \"copy-image\"}, \"stores\": [\"fast\", \"cheap\"]}\u0027","commit_id":"518192ab2aeee031364048fc963677e04becc58e"},{"author":{"_account_id":18002,"name":"John Fulton","email":"fulton@redhat.com","username":"fultonj"},"change_message_id":"f655c89aad9f485be3dda75a081ab08ee9002b6b","unresolved":false,"context_lines":[{"line_number":749,"context_line":"                    \"be both specified\")"},{"line_number":750,"context_line":"            raise exc.HTTPBadRequest(explanation\u003dmsg)"},{"line_number":751,"context_line":"    # Validate each store"},{"line_number":752,"context_line":"    for store in stores:"},{"line_number":753,"context_line":"        glance_store.get_store_from_store_identifier(store)"},{"line_number":754,"context_line":"    return stores"}],"source_content_type":"text/x-python","patch_set":9,"id":"3fa7e38b_e436f64f","line":752,"updated":"2019-12-03 21:10:08.000000000","message":"Thanks for this patch.\n\nIs it possible this won\u0027t handle splitting the comma delimited list? \n\nI tried this patch and it seemed to treat my two stores as if they were one.\n\n+ curl -g -i -X POST http://10.20.1.26:9292/v2/images/c0520fda-6006-42cc-974a-2d60f31c9444/import -H \u0027x-image-meta-store: central, dcn0\u0027 -H \u0027User-Agent: python-glanceclient\u0027 -H \u0027Content-Type: application/json\u0027 -H \u0027X-Auth-Token: gAAAAABd5pZGg4oSlnE4gF9ldcmwt1ZkoGd3gAMUZjgqqRM5Pbw4ZOS5b45gy8yD9oHrwgBboFXFYMiOfsCOg_WL1rZA2-Reh2mLU2wQeSqHxdkmCVRg3Fkhe37yOb-lBhIvf6SUwfqYyrHzJHp51qz4-PG6I7ltwQrd8A3m-fg3_Ddxpvo6c4o\u0027 -d \u0027{\"method\": {\"name\": \"glance-direct\"}}\u0027\nHTTP/1.1 409 Conflict\nContent-Length: 164\nContent-Type: text/html; charset\u003dUTF-8\nX-Openstack-Request-Id: req-8d73b28a-85d2-4d54-8a7e-742d2bbab93d\nDate: Tue, 03 Dec 2019 17:07:20 GMT\n\n\u003chtml\u003e\n \u003chead\u003e\n  \u003ctitle\u003e409 Conflict\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n  \u003ch1\u003e409 Conflict\u003c/h1\u003e\n  Store for identifier central, dcn0 not found\u003cbr /\u003e\u003cbr /\u003e\n\n\n\n \u003c/body\u003e\n\u003c/html\u003e","commit_id":"42310fc6295cf1423cf08fab3810e27a19841b0b"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"1a936270f2e70caf70d88fd7c77b71de822bd8dd","unresolved":false,"context_lines":[{"line_number":749,"context_line":"                    \"be both specified\")"},{"line_number":750,"context_line":"            raise exc.HTTPBadRequest(explanation\u003dmsg)"},{"line_number":751,"context_line":"    # Validate each store"},{"line_number":752,"context_line":"    for store in stores:"},{"line_number":753,"context_line":"        glance_store.get_store_from_store_identifier(store)"},{"line_number":754,"context_line":"    return stores"}],"source_content_type":"text/x-python","patch_set":9,"id":"3fa7e38b_04e792ae","line":752,"in_reply_to":"3fa7e38b_e436f64f","updated":"2019-12-03 21:20:34.000000000","message":"Yes John,\nYou are right this patch doesn’t handles , separated splitting of stores, i have made those changes in child patch for testing purpose. So in this case instead passing multiple stores in headers you can pass it as a body.\n\ne.g. d \u0027{\"method\": {\"name\": \"glance-direct\"}, “stores”: [“central”, “dcn0”]}\u0027","commit_id":"42310fc6295cf1423cf08fab3810e27a19841b0b"}],"glance/location.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"086ced12b4cf62e8e525ff2727a7795e2bf6da62","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        hashing_algo \u003d CONF[\u0027hashing_algorithm\u0027]"},{"line_number":453,"context_line":"        locations \u003d []"},{"line_number":454,"context_line":"        for backend in backends:"},{"line_number":455,"context_line":"            (location, size, checksum,"},{"line_number":456,"context_line":"             multihash, loc_meta) \u003d self.store_api.add_with_multihash("},{"line_number":457,"context_line":"                CONF,"},{"line_number":458,"context_line":"                self.image.image_id,"},{"line_number":459,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":460,"context_line":"                                     CONF.image_size_cap),"},{"line_number":461,"context_line":"                size,"},{"line_number":462,"context_line":"                backend,"},{"line_number":463,"context_line":"                hashing_algo,"},{"line_number":464,"context_line":"                context\u003dself.context,"},{"line_number":465,"context_line":"                verifier\u003dverifier)"},{"line_number":466,"context_line":"            locations.append({\u0027url\u0027: location, \u0027metadata\u0027: loc_meta,"},{"line_number":467,"context_line":"                              \u0027status\u0027: \u0027active\u0027})"},{"line_number":468,"context_line":"            if verifier is not None:"},{"line_number":469,"context_line":"                try:"},{"line_number":470,"context_line":"                    verifier.verify()"},{"line_number":471,"context_line":"                    msg \u003d _LI(\"Successfully verified signature for image %s\")"},{"line_number":472,"context_line":"                    LOG.info(msg, self.image.image_id)"},{"line_number":473,"context_line":"                except crypto_exception.InvalidSignature:"},{"line_number":474,"context_line":"                    for loc in locations:"},{"line_number":475,"context_line":"                        self.store_api.delete(loc[\u0027url\u0027],"},{"line_number":476,"context_line":"                                              loc[\u0027metadata\u0027].get(\u0027backend\u0027),"},{"line_number":477,"context_line":"                                              context\u003dself.context)"},{"line_number":478,"context_line":"                    raise cursive_exception.SignatureVerificationError("},{"line_number":479,"context_line":"                        _(\u0027Signature verification failed\u0027)"},{"line_number":480,"context_line":"                    )"},{"line_number":481,"context_line":""},{"line_number":482,"context_line":"            try:"},{"line_number":483,"context_line":"                data.seek(0)"},{"line_number":484,"context_line":"            except (UnsupportedOperation, AttributeError):"},{"line_number":485,"context_line":"                data \u003d self.store_api.get(location, backend,"},{"line_number":486,"context_line":"                                          context\u003dself.context)[0]"},{"line_number":487,"context_line":""},{"line_number":488,"context_line":"        self.image.locations \u003d locations"},{"line_number":489,"context_line":"        self.image.checksum \u003d checksum"},{"line_number":490,"context_line":"        self.image.os_hash_value \u003d multihash"},{"line_number":491,"context_line":"        self.image.size \u003d size"},{"line_number":492,"context_line":"        self.image.os_hash_algo \u003d hashing_algo"},{"line_number":493,"context_line":""},{"line_number":494,"context_line":"    def _set_locations_no_multi_stores(self, data, verifier, size\u003dNone):"},{"line_number":495,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_bd7285e3","line":492,"range":{"start_line":455,"start_character":12,"end_line":492,"end_character":46},"updated":"2019-11-29 05:28:14.000000000","message":"we can avoid this duplication IMO, same code is used in below function as well","commit_id":"71535810973f82d2b5cb34474b483588e57d3fcb"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"0d5c11b14cf9bf4c4c953a545706070ae14c4181","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        hashing_algo \u003d CONF[\u0027hashing_algorithm\u0027]"},{"line_number":453,"context_line":"        locations \u003d []"},{"line_number":454,"context_line":"        for backend in backends:"},{"line_number":455,"context_line":"            (location, size, checksum,"},{"line_number":456,"context_line":"             multihash, loc_meta) \u003d self.store_api.add_with_multihash("},{"line_number":457,"context_line":"                CONF,"},{"line_number":458,"context_line":"                self.image.image_id,"},{"line_number":459,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":460,"context_line":"                                     CONF.image_size_cap),"},{"line_number":461,"context_line":"                size,"},{"line_number":462,"context_line":"                backend,"},{"line_number":463,"context_line":"                hashing_algo,"},{"line_number":464,"context_line":"                context\u003dself.context,"},{"line_number":465,"context_line":"                verifier\u003dverifier)"},{"line_number":466,"context_line":"            locations.append({\u0027url\u0027: location, \u0027metadata\u0027: loc_meta,"},{"line_number":467,"context_line":"                              \u0027status\u0027: \u0027active\u0027})"},{"line_number":468,"context_line":"            if verifier is not None:"},{"line_number":469,"context_line":"                try:"},{"line_number":470,"context_line":"                    verifier.verify()"},{"line_number":471,"context_line":"                    msg \u003d _LI(\"Successfully verified signature for image %s\")"},{"line_number":472,"context_line":"                    LOG.info(msg, self.image.image_id)"},{"line_number":473,"context_line":"                except crypto_exception.InvalidSignature:"},{"line_number":474,"context_line":"                    for loc in locations:"},{"line_number":475,"context_line":"                        self.store_api.delete(loc[\u0027url\u0027],"},{"line_number":476,"context_line":"                                              loc[\u0027metadata\u0027].get(\u0027backend\u0027),"},{"line_number":477,"context_line":"                                              context\u003dself.context)"},{"line_number":478,"context_line":"                    raise cursive_exception.SignatureVerificationError("},{"line_number":479,"context_line":"                        _(\u0027Signature verification failed\u0027)"},{"line_number":480,"context_line":"                    )"},{"line_number":481,"context_line":""},{"line_number":482,"context_line":"            try:"},{"line_number":483,"context_line":"                data.seek(0)"},{"line_number":484,"context_line":"            except (UnsupportedOperation, AttributeError):"},{"line_number":485,"context_line":"                data \u003d self.store_api.get(location, backend,"},{"line_number":486,"context_line":"                                          context\u003dself.context)[0]"},{"line_number":487,"context_line":""},{"line_number":488,"context_line":"        self.image.locations \u003d locations"},{"line_number":489,"context_line":"        self.image.checksum \u003d checksum"},{"line_number":490,"context_line":"        self.image.os_hash_value \u003d multihash"},{"line_number":491,"context_line":"        self.image.size \u003d size"},{"line_number":492,"context_line":"        self.image.os_hash_algo \u003d hashing_algo"},{"line_number":493,"context_line":""},{"line_number":494,"context_line":"    def _set_locations_no_multi_stores(self, data, verifier, size\u003dNone):"},{"line_number":495,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_03efba1d","line":492,"range":{"start_line":455,"start_character":12,"end_line":492,"end_character":46},"in_reply_to":"3fa7e38b_bd7285e3","updated":"2019-11-29 08:34:44.000000000","message":"I would like to limit too, but it\u0027s not the exact same code.\nHere we call \u0027store_api.add_with_multihash\u0027 whereas \u0027store_api.add_to_backend_with_multihash\u0027 is called in the other method. The except code is not the same too.\nI will think on how to minimize this duplication.","commit_id":"71535810973f82d2b5cb34474b483588e57d3fcb"},{"author":{"_account_id":5202,"name":"Erno Kuvaja","email":"jokke@usr.fi","username":"jokke"},"change_message_id":"cb2144a7cfdab73f6b09459ce781a63e64cc5008","unresolved":false,"context_lines":[{"line_number":447,"context_line":"        :param size: data size"},{"line_number":448,"context_line":"        :return:"},{"line_number":449,"context_line":"        \"\"\""},{"line_number":450,"context_line":"        hashing_algo \u003d CONF[\u0027hashing_algorithm\u0027]"},{"line_number":451,"context_line":"        if CONF.enabled_backends:"},{"line_number":452,"context_line":"            (location, size, checksum,"},{"line_number":453,"context_line":"             multihash, loc_meta) \u003d self.store_api.add_with_multihash("},{"line_number":454,"context_line":"                CONF,"},{"line_number":455,"context_line":"                self.image.image_id,"},{"line_number":456,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":457,"context_line":"                                     CONF.image_size_cap),"},{"line_number":458,"context_line":"                size,"},{"line_number":459,"context_line":"                store,"},{"line_number":460,"context_line":"                hashing_algo,"},{"line_number":461,"context_line":"                context\u003dself.context,"},{"line_number":462,"context_line":"                verifier\u003dverifier)"},{"line_number":463,"context_line":"        else:"},{"line_number":464,"context_line":"            (location,"},{"line_number":465,"context_line":"             size,"},{"line_number":466,"context_line":"             checksum,"},{"line_number":467,"context_line":"             multihash,"},{"line_number":468,"context_line":"             loc_meta) \u003d self.store_api.add_to_backend_with_multihash("},{"line_number":469,"context_line":"                CONF,"},{"line_number":470,"context_line":"                self.image.image_id,"},{"line_number":471,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":472,"context_line":"                                     CONF.image_size_cap),"},{"line_number":473,"context_line":"                size,"},{"line_number":474,"context_line":"                hashing_algo,"},{"line_number":475,"context_line":"                context\u003dself.context,"},{"line_number":476,"context_line":"                verifier\u003dverifier)"},{"line_number":477,"context_line":"        self._verify_upload(verifier, location, loc_meta)"},{"line_number":478,"context_line":"        self.image.locations.append({\u0027url\u0027: location, \u0027metadata\u0027: loc_meta,"},{"line_number":479,"context_line":"                                     \u0027status\u0027: \u0027active\u0027})"},{"line_number":480,"context_line":"        self.image.checksum \u003d checksum"},{"line_number":481,"context_line":"        self.image.os_hash_value \u003d multihash"},{"line_number":482,"context_line":"        self.image.size \u003d size"},{"line_number":483,"context_line":"        self.image.os_hash_algo \u003d hashing_algo"},{"line_number":484,"context_line":""},{"line_number":485,"context_line":"    def _verify_upload(self, verifier, location, loc_meta):"},{"line_number":486,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_0edd0512","line":483,"range":{"start_line":450,"start_character":0,"end_line":483,"end_character":46},"updated":"2020-01-27 13:30:37.000000000","message":"Sorry for not noticing this before. We probably need to change to logic here for a bit, specially with the \u0027copy-image\u0027 coming into the picture. This logic has couple of major risks:\n\n1) If the system wide hashing algo changes between the original creation of the image and copying it we will be overwriting the multihash from the metadata. There is no way for the enduser to know that the image is actually the same image they got originally as the hash (and algorithm) has changed during the image lifetime. The immutability promise has always been the top most priority for Glance and we should address it here too.\n\nThere might be protection for this already in the codepath. (I\u0027m not sure how the image will behave if internally try to change the values.) But that will just cause that the second concern of mine is not valid and all cases of this first one will fail without way of recovering from it.\n\n2) If there is corruption of the data between the first and last _upload_to_store, we silently ignore it and just write the last hash to the image metadata.\n\nSimple ways to address these risks:\n1) If the image is active and has multihash values in it we use the hashing algo from the image instead of the value in the config file.\n2) If the image has os_hash_value we will just compare the checksum we calculated instead of blindly updating it. Should these two not match we will need to raise an exception and log it (error) to indicate that there is some serious issues in our datapath.\n\nNOTE: Our tasks revert logic needs to take this into account. If we are reverting the image back to queued without any locations left, we need to make sure we clean up the multihash metadata as well. (This might be the most difficult part if we indeed do have protections against changing these values in the codepath.)","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"aca7c09d18f9d7257a02e4c668d327ffe290c60d","unresolved":false,"context_lines":[{"line_number":447,"context_line":"        :param size: data size"},{"line_number":448,"context_line":"        :return:"},{"line_number":449,"context_line":"        \"\"\""},{"line_number":450,"context_line":"        hashing_algo \u003d CONF[\u0027hashing_algorithm\u0027]"},{"line_number":451,"context_line":"        if CONF.enabled_backends:"},{"line_number":452,"context_line":"            (location, size, checksum,"},{"line_number":453,"context_line":"             multihash, loc_meta) \u003d self.store_api.add_with_multihash("},{"line_number":454,"context_line":"                CONF,"},{"line_number":455,"context_line":"                self.image.image_id,"},{"line_number":456,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":457,"context_line":"                                     CONF.image_size_cap),"},{"line_number":458,"context_line":"                size,"},{"line_number":459,"context_line":"                store,"},{"line_number":460,"context_line":"                hashing_algo,"},{"line_number":461,"context_line":"                context\u003dself.context,"},{"line_number":462,"context_line":"                verifier\u003dverifier)"},{"line_number":463,"context_line":"        else:"},{"line_number":464,"context_line":"            (location,"},{"line_number":465,"context_line":"             size,"},{"line_number":466,"context_line":"             checksum,"},{"line_number":467,"context_line":"             multihash,"},{"line_number":468,"context_line":"             loc_meta) \u003d self.store_api.add_to_backend_with_multihash("},{"line_number":469,"context_line":"                CONF,"},{"line_number":470,"context_line":"                self.image.image_id,"},{"line_number":471,"context_line":"                utils.LimitingReader(utils.CooperativeReader(data),"},{"line_number":472,"context_line":"                                     CONF.image_size_cap),"},{"line_number":473,"context_line":"                size,"},{"line_number":474,"context_line":"                hashing_algo,"},{"line_number":475,"context_line":"                context\u003dself.context,"},{"line_number":476,"context_line":"                verifier\u003dverifier)"},{"line_number":477,"context_line":"        self._verify_upload(verifier, location, loc_meta)"},{"line_number":478,"context_line":"        self.image.locations.append({\u0027url\u0027: location, \u0027metadata\u0027: loc_meta,"},{"line_number":479,"context_line":"                                     \u0027status\u0027: \u0027active\u0027})"},{"line_number":480,"context_line":"        self.image.checksum \u003d checksum"},{"line_number":481,"context_line":"        self.image.os_hash_value \u003d multihash"},{"line_number":482,"context_line":"        self.image.size \u003d size"},{"line_number":483,"context_line":"        self.image.os_hash_algo \u003d hashing_algo"},{"line_number":484,"context_line":""},{"line_number":485,"context_line":"    def _verify_upload(self, verifier, location, loc_meta):"},{"line_number":486,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_15dae91b","line":483,"range":{"start_line":450,"start_character":0,"end_line":483,"end_character":46},"in_reply_to":"3fa7e38b_0edd0512","updated":"2020-01-27 20:48:41.000000000","message":"Good catch and clear explanation :)\nI\u0027ll modify the method _verify_upload to add these necessary checks. We should be able to keep lines 478 to 483 as if we go through _verify_upload without getting an exception, the hash values are either the same or not yet set on the image.","commit_id":"4e6bc6a0a37f60093312aae68de5aaf79a75bf7e"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":410,"context_line":""},{"line_number":411,"context_line":""},{"line_number":412,"context_line":"class ImageProxy(glance.domain.proxy.Image):"},{"line_number":413,"context_line":""},{"line_number":414,"context_line":"    locations \u003d _locations_proxy(\u0027image\u0027, \u0027locations\u0027)"},{"line_number":415,"context_line":""},{"line_number":416,"context_line":"    def __init__(self, image, context, store_api, store_utils):"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_4f9577e2","side":"PARENT","line":413,"updated":"2020-02-10 05:28:36.000000000","message":"ditto","commit_id":"8649fdc2a293009899d2aa918ec360e30adc8e77"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":201,"context_line":"           from an image."},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    \"\"\""},{"line_number":204,"context_line":""},{"line_number":205,"context_line":"    def __init__(self, image_proxy, value):"},{"line_number":206,"context_line":"        self.image_proxy \u003d image_proxy"},{"line_number":207,"context_line":"        if isinstance(value, list):"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_6ff4f356","line":204,"updated":"2020-02-10 05:28:36.000000000","message":"Unnecessary change","commit_id":"8b7610ca1fa4de504c5115b1f8177cdc0d6007ac"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":358,"context_line":"    :param target: the image object on which to add the proxy"},{"line_number":359,"context_line":"    :param attr: the property proxy we want to hook"},{"line_number":360,"context_line":"    \"\"\""},{"line_number":361,"context_line":""},{"line_number":362,"context_line":"    def get_attr(self):"},{"line_number":363,"context_line":"        value \u003d getattr(getattr(self, target), attr)"},{"line_number":364,"context_line":"        return StoreLocations(self, value)"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_8ff12f67","line":361,"updated":"2020-02-10 05:28:36.000000000","message":"ditto","commit_id":"8b7610ca1fa4de504c5115b1f8177cdc0d6007ac"}],"glance/notifier.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"c7ef4846888fad0e77a64b72d341f85637ece1ce","unresolved":false,"context_lines":[{"line_number":429,"context_line":""},{"line_number":430,"context_line":"        notify_error \u003d self.notifier.error"},{"line_number":431,"context_line":"        try:"},{"line_number":432,"context_line":"            self.repo.set_data(data, size, backend\u003dbackend)"},{"line_number":433,"context_line":"        except glance_store.StorageFull as e:"},{"line_number":434,"context_line":"            msg \u003d (_(\"Image storage media is full: %s\") %"},{"line_number":435,"context_line":"                   encodeutils.exception_to_unicode(e))"}],"source_content_type":"text/x-python","patch_set":11,"id":"3fa7e38b_bac33239","line":432,"updated":"2019-12-04 05:29:37.000000000","message":"you need to pass set_active\u003dset_active here otherwise in next layer it will pick default value which will be True and image will be set to active after 1st iteration of Import and next will fail with state transition active to active not allowed.","commit_id":"b95652cbb2de12df6dd42276eb22e342dfa27d38"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"df3fc14a5a3b828331f38a3825ebeee1da2ebecf","unresolved":false,"context_lines":[{"line_number":429,"context_line":""},{"line_number":430,"context_line":"        notify_error \u003d self.notifier.error"},{"line_number":431,"context_line":"        try:"},{"line_number":432,"context_line":"            self.repo.set_data(data, size, backend\u003dbackend)"},{"line_number":433,"context_line":"        except glance_store.StorageFull as e:"},{"line_number":434,"context_line":"            msg \u003d (_(\"Image storage media is full: %s\") %"},{"line_number":435,"context_line":"                   encodeutils.exception_to_unicode(e))"}],"source_content_type":"text/x-python","patch_set":11,"id":"3fa7e38b_3ce3b336","line":432,"in_reply_to":"3fa7e38b_bac33239","updated":"2019-12-04 18:08:13.000000000","message":"Done","commit_id":"b95652cbb2de12df6dd42276eb22e342dfa27d38"}],"glance/quota/__init__.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"c7ef4846888fad0e77a64b72d341f85637ece1ce","unresolved":false,"context_lines":[{"line_number":315,"context_line":"            data \u003d utils.LimitingReader("},{"line_number":316,"context_line":"                data, remaining, exception_class\u003dexception.StorageQuotaFull)"},{"line_number":317,"context_line":""},{"line_number":318,"context_line":"        self.image.set_data(data, size\u003dsize, backend\u003dbackend)"},{"line_number":319,"context_line":""},{"line_number":320,"context_line":"        # NOTE(jbresnah) If two uploads happen at the same time and neither"},{"line_number":321,"context_line":"        # properly sets the size attribute[1] then there is a race condition"}],"source_content_type":"text/x-python","patch_set":11,"id":"3fa7e38b_5ac23e36","line":318,"updated":"2019-12-04 05:29:37.000000000","message":"you need to pass set_active\u003dset_active here otherwise in next layer it will pick default value which will be True and image will be set to active after 1st iteration of Import and next will fail with state transition active to active not allowed.","commit_id":"b95652cbb2de12df6dd42276eb22e342dfa27d38"},{"author":{"_account_id":30054,"name":"Grégoire Unbekandt","email":"gregoire.unbekandt@gmail.com","username":"yebinama"},"change_message_id":"df3fc14a5a3b828331f38a3825ebeee1da2ebecf","unresolved":false,"context_lines":[{"line_number":315,"context_line":"            data \u003d utils.LimitingReader("},{"line_number":316,"context_line":"                data, remaining, exception_class\u003dexception.StorageQuotaFull)"},{"line_number":317,"context_line":""},{"line_number":318,"context_line":"        self.image.set_data(data, size\u003dsize, backend\u003dbackend)"},{"line_number":319,"context_line":""},{"line_number":320,"context_line":"        # NOTE(jbresnah) If two uploads happen at the same time and neither"},{"line_number":321,"context_line":"        # properly sets the size attribute[1] then there is a race condition"}],"source_content_type":"text/x-python","patch_set":11,"id":"3fa7e38b_9cd4274d","line":318,"in_reply_to":"3fa7e38b_5ac23e36","updated":"2019-12-04 18:08:13.000000000","message":"Done","commit_id":"b95652cbb2de12df6dd42276eb22e342dfa27d38"}],"glance/tests/unit/test_notifier.py":[{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":30,"context_line":"import glance.tests.unit.utils as unit_test_utils"},{"line_number":31,"context_line":"from glance.tests import utils"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"DATETIME \u003d datetime.datetime(2012, 5, 16, 15, 27, 36, 325355)"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_af83cba9","side":"PARENT","line":33,"updated":"2020-02-10 05:28:36.000000000","message":"ditto","commit_id":"8649fdc2a293009899d2aa918ec360e30adc8e77"},{"author":{"_account_id":9303,"name":"Abhishek Kekane","email":"akekane@redhat.com","username":"abhishekkekane"},"change_message_id":"bc1075afc12a36452c7ee4e3e55a4b7d341c3629","unresolved":false,"context_lines":[{"line_number":32,"context_line":""},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"DATETIME \u003d datetime.datetime(2012, 5, 16, 15, 27, 36, 325355)"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"UUID1 \u003d \u0027c80a1a6c-bd1f-41c5-90ee-81afedb1d58d\u0027"},{"line_number":38,"context_line":"USER1 \u003d \u002754492ba0-f4df-4e4e-be62-27f4d76b29cf\u0027"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_cf80879f","side":"PARENT","line":35,"updated":"2020-02-10 05:28:36.000000000","message":"ditto","commit_id":"8649fdc2a293009899d2aa918ec360e30adc8e77"}]}
