)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"56a52eea7216be58dafffd1ee86e87ce193c119f","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Replace python-glanceclient with openstacksdk"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"The image download service previously used python-glanceclient to"},{"line_number":10,"context_line":"communicate with Glance. Since openstacksdk is already a dependency"},{"line_number":11,"context_line":"and provides an image service proxy, replace glanceclient usage with"},{"line_number":12,"context_line":"openstacksdk\u0027s Connection.image.download_image()."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"bd808b8c_10c9d63b","line":9,"range":{"start_line":9,"start_character":19,"end_line":9,"end_character":26},"updated":"2026-11-05 18:11:12.000000000","message":"nit: workflow, process, functionality.\n\n\nits not really a service in a service architecture sense or service domain pattern sense","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7c0e5b4a11996a656e3a63658955425673da626c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"1d0d4d96_1e93a827","updated":"2026-11-02 16:38:39.000000000","message":"Failure is legit, need to fix.","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1d1123b184012d6e31ccafda1dc0677a6ab66c65","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"87aae972_aa493f13","updated":"2026-11-03 01:24:28.000000000","message":"ill make tiem to review this properly btu the fact that tempest is now passign the fpga programing test is at least promising.\n\ni want to review the actul cybrog logs to see if it really downloaded an image form glance or not but this is progress so +1 for now","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"5d497945a38e578a6b7805abadfbb5a6c0389d05","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"bb016be9_33698da6","in_reply_to":"22558bf0_d32f5b71","updated":"2026-11-04 14:27:31.000000000","message":"so there are 2 programing flwos and it soudn like the second wone is broken\n\nyou can program devices dreictly or you can specify a glance uuid in the device profile\n\nin the device profiel state it sment to start the programign on bind and complete it before we sent the binding completed event to nova\u0027s exteranl events api.\n\nthe current tempest test i tbelive only use the api triggferd path\n\nbut we proably need test coverage for the second path.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"94427cb86a986264eb4a5555fa141b34a6b22ebc","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"987cbd88_1783b5b0","in_reply_to":"43bef180_cbf2039d","updated":"2026-11-05 04:38:05.000000000","message":"chandans work to add nvme device emulation is proably the best bet.\n\nthere is no reason not to add supprot in the nvme driver to \"program\" a glance image to an nvme device.\n\nwe can proably just use qemu-img to do that can call it a day.\n\nbut ya for now it think if it works with the fake-driver that a good starting point\nthe test seams to at least be passing https://d09a8b23dc71a2c4560a-b9312bd10473a56ac2ea34b331082425.ssl.cf1.rackcdn.com/openstack/00b1fe46659c406d92b1136ea8eb96ba/testr_results.html\n\nbut ill check out the review properly tomorrow and we can figure out how to test with somethign liek the pci-sim later.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"0fe3a93b465e097c3d256f68452aafe6ff93e4a3","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"22558bf0_d32f5b71","in_reply_to":"65dc1fa9_0a00103a","updated":"2026-11-04 02:53:25.000000000","message":"Sorry, I think I was mistaken ... I didn\u0027t realize the difference between the bind step above vs the program step in the test. The output above was from the bind, before the separate programming request.\n\nThe programming request shows the download on the Glance side [1]:\n\n```\nNov 03 19:21:13.874674 np1f7f45fc4c744 devstack@g-api.service[80623]: DEBUG glance_store._drivers.filesystem [None req-4d56d222-890f-4334-874b-f86dac038a9a admin admin] Found image at /opt/stack/data/glance/images/c159c0dc-0ae4-43eb-9a80-1db487ca25ab. Returning in ChunkedFile. {{(pid\u003d80623) get /opt/stack/data/venv/lib/python3.13/site-packages/glance_store/_drivers/filesystem.py:724}}\nNov 03 19:21:13.889790 np1f7f45fc4c744 devstack@g-api.service[80623]: DEBUG glance.image_cache [None req-4d56d222-890f-4334-874b-f86dac038a9a admin admin] Tee\u0027ing image \u0027c159c0dc-0ae4-43eb-9a80-1db487ca25ab\u0027 into cache {{(pid\u003d80623) get_caching_iter /opt/stack/glance/glance/image_cache/__init__.py:356}}\nNov 03 19:21:14.014403 np1f7f45fc4c744 devstack@g-api.service[80623]: DEBUG glance.image_cache.drivers.centralized_db [None req-4d56d222-890f-4334-874b-f86dac038a9a admin admin] Fetch finished, moving \u0027/opt/stack/data/glance/cache/incomplete/c159c0dc-0ae4-43eb-9a80-1db487ca25ab\u0027 to \u0027/opt/stack/data/glance/cache/c159c0dc-0ae4-43eb-9a80-1db487ca25ab\u0027 {{(pid\u003d80623) commit /opt/stack/glance/glance/image_cache/drivers/centralized_db.py:243}}\nNov 03 19:21:14.031331 np1f7f45fc4c744 devstack@g-api.service[80623]: DEBUG glance.image_cache.drivers.centralized_db [None req-4d56d222-890f-4334-874b-f86dac038a9a admin admin] Image cached successfully. {{(pid\u003d80623) commit /opt/stack/glance/glance/image_cache/drivers/centralized_db.py:258}}\nNov 03 19:21:14.031606 np1f7f45fc4c744 devstack@g-api.service[80623]: [pid: 80623|app: 0|req: 18/34] 127.0.0.1 () {40 vars in 954 bytes} [Tue Nov  3 19:21:13 2026] GET /v2/images/c159c0dc-0ae4-43eb-9a80-1db487ca25ab/file \u003d\u003e generated 21692416 bytes in 170 msecs (HTTP/1.1 200) 4 headers in 191 bytes (333 switches on core 0)\n```\n\n[1] https://zuul.opendev.org/t/openstack/build/4582718ee94e48069a129fcd83b38643/log/controller/logs/screen-g-api.txt#1334","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"fb1036cd1879728b80c8d90b4bafee6fc5c2d76c","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"9f6d901b_2bb17f51","in_reply_to":"6a00058d_8b1f4862","updated":"2026-11-04 19:57:13.000000000","message":"Gotcha. Yes you are right that the current FPGA test exercises the API triggered path. I tested the program-on-bind path on my Devstack and it also works. \n\nI wrote up a test locally to do that ^ so I can push a patch for that since there is value in covering both paths.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"c0f22ecd5676bd8ab991150c1f0cc90428da1afa","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"65dc1fa9_0a00103a","in_reply_to":"87aae972_aa493f13","updated":"2026-11-04 02:30:43.000000000","message":"I looked through the logs and I think it is not actually downloading an image for the FPGA test, for example I see [1]:\n\n```\nStart bind jobs for ARQ(372b3a49-36b9-4b7a-afa4-f8ad587e7c87) with deployable(8b2e9d67-eca5-48cd-9d3b-5b8028931933)\nGet bitstream metadata for deployable(uuid:8b2e9d67-eca5-48cd-9d3b-5b8028931933).\nNo programming is required.\n```\n\nI did figure out how to make it need programming with the help of AI, so I can upload a patch for that to try.\n\n[1] https://zuul.opendev.org/t/openstack/build/bb3a6797f31c4b54b25b8d3476027f15/log/controller/logs/screen-cyborg-cond.txt#983","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4d1829d4f4b17b8faa9c8f8e33103418e82dce38","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"43bef180_cbf2039d","in_reply_to":"9f6d901b_2bb17f51","updated":"2026-11-04 21:08:47.000000000","message":"I proposed the basics of the test here:\n\nhttps://review.opendev.org/c/openstack/cyborg-tempest-plugin/+/1014182\n\nbut not sure the best way to make it be able to work with pci-sim yet.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8bca00307e993f71f8cb6caa9c890fe1f708bd4f","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"6a00058d_8b1f4862","in_reply_to":"bb016be9_33698da6","updated":"2026-11-04 14:37:32.000000000","message":"also just to be clear the reason we have 2 path is basiclly there was the concept that you coudl have a bunch of FPGAs that a oeprte woudl use cybrog to program via the api, and then the would update there pci  whitelist (or have it preconfigured)\nso that when the bitstream is installed and with a bitstream that expsoed pcie devices they could then be consumed seperatly by a user rquestable bitstream\n\ni.e. the admin program one fpga with a function that end user can then concume in a 1deployable to n consumers fassion as ech of the fpga provied sriov vf could be discoverd and provided indepently\n\nthe abltiy to spcify the bitstream image in the device profile is caterign to the usecase where the operator has a catalong of bitstream images for diffent acclerator function where each function consumes an entrie fpga and is dedicated to a singel vm. in that flow the admin upload the bistream to glance and create a set of device profiles to to request them dynmaicly.\n\nin that flow the programing happens as a sideffect of device bind so they do not need to pre allocate fpga to server specific allceration fucntions up front\n\nwe just track the inventores of the generic fpgas and use traits to enfore image and device compaitblity.\n\ni dont think this docuemetned anywere i was just in the ptg session when this was being designed so i may have missed some details.\n\nthere are some spec on this topic but agaisn i dont knwo how much detail they go into off hand.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"ad85db0c9f08bb2710a56aa57bc3eb5065fa764b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"f0a2912f_3afb93a1","updated":"2026-11-04 14:17:09.000000000","message":"ill leave this open for another day or two but i think this is ready. \n\nim happy to review if there are addtioanl refinements","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"da364b0d5365025db28ea201724705386991d676","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"6c1e7f93_f7f949bc","updated":"2026-11-04 05:36:24.000000000","message":"overall looks good.\n\nOne less dependency to worry about.","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"}],"cyborg/image/api.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"cb8f3be556f8cb900f22ddaf9df01e655592fcb8","unresolved":true,"context_lines":[{"line_number":53,"context_line":"        :param data: A file object to use in downloading image data."},{"line_number":54,"context_line":"        :param dest_path: Filepath to transfer image bits to."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"        Note that because of the poor design of the"},{"line_number":57,"context_line":"        `glance.ImageService.download` method, the function returns different"},{"line_number":58,"context_line":"        things depending on what arguments are passed to it. If a data argument"},{"line_number":59,"context_line":"        is supplied but no dest_path is specified (only done in the XenAPI virt"},{"line_number":60,"context_line":"        driver\u0027s image.utils module) then None is returned from the method. If"},{"line_number":61,"context_line":"        the data argument is not specified but a destination path *is*"},{"line_number":62,"context_line":"        specified, then a writeable file handle to the destination path is"},{"line_number":63,"context_line":"        constructed in the method and the image bits written to that file, and"},{"line_number":64,"context_line":"        again, None is returned from the method. If no data argument is"},{"line_number":65,"context_line":"        supplied and no dest_path argument is supplied (VMWare and XenAPI virt"},{"line_number":66,"context_line":"        drivers), then the method returns an iterator to the image bits that"},{"line_number":67,"context_line":"        the caller uses to write to wherever location it wants."},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"        I think the above points to just how hacky/wacky all of this code is,"},{"line_number":70,"context_line":"        and the reason it needs to be cleaned up and standardized across the"},{"line_number":71,"context_line":"        virt driver callers."},{"line_number":72,"context_line":"        \"\"\""},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"        session, image_id \u003d self._get_session_and_image_id(context, id_or_uri)"}],"source_content_type":"text/x-python","patch_set":2,"id":"f1323629_0f85d170","side":"PARENT","line":71,"range":{"start_line":56,"start_character":7,"end_line":71,"end_character":28},"updated":"2026-11-02 13:21:21.000000000","message":"ah right this was form nova","commit_id":"8f58f18b90de98a047dabc93a7c5f41b0a4ae656"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1d1123b184012d6e31ccafda1dc0677a6ab66c65","unresolved":false,"context_lines":[{"line_number":53,"context_line":"        :param data: A file object to use in downloading image data."},{"line_number":54,"context_line":"        :param dest_path: Filepath to transfer image bits to."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"        Note that because of the poor design of the"},{"line_number":57,"context_line":"        `glance.ImageService.download` method, the function returns different"},{"line_number":58,"context_line":"        things depending on what arguments are passed to it. If a data argument"},{"line_number":59,"context_line":"        is supplied but no dest_path is specified (only done in the XenAPI virt"},{"line_number":60,"context_line":"        driver\u0027s image.utils module) then None is returned from the method. If"},{"line_number":61,"context_line":"        the data argument is not specified but a destination path *is*"},{"line_number":62,"context_line":"        specified, then a writeable file handle to the destination path is"},{"line_number":63,"context_line":"        constructed in the method and the image bits written to that file, and"},{"line_number":64,"context_line":"        again, None is returned from the method. If no data argument is"},{"line_number":65,"context_line":"        supplied and no dest_path argument is supplied (VMWare and XenAPI virt"},{"line_number":66,"context_line":"        drivers), then the method returns an iterator to the image bits that"},{"line_number":67,"context_line":"        the caller uses to write to wherever location it wants."},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"        I think the above points to just how hacky/wacky all of this code is,"},{"line_number":70,"context_line":"        and the reason it needs to be cleaned up and standardized across the"},{"line_number":71,"context_line":"        virt driver callers."},{"line_number":72,"context_line":"        \"\"\""},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"        session, image_id \u003d self._get_session_and_image_id(context, id_or_uri)"}],"source_content_type":"text/x-python","patch_set":2,"id":"2d188125_0be0deac","side":"PARENT","line":71,"range":{"start_line":56,"start_character":7,"end_line":71,"end_character":28},"in_reply_to":"f1323629_0f85d170","updated":"2026-11-03 01:24:28.000000000","message":"Acknowledged","commit_id":"8f58f18b90de98a047dabc93a7c5f41b0a4ae656"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"56a52eea7216be58dafffd1ee86e87ce193c119f","unresolved":false,"context_lines":[{"line_number":38,"context_line":"        :param id_or_uri: A UUID identifier or an image URI to look up image"},{"line_number":39,"context_line":"                          information for."},{"line_number":40,"context_line":"        \"\"\""},{"line_number":41,"context_line":"        return glance.get_remote_image_service(context, id_or_uri)"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    def download(self, context, id_or_uri, data\u003dNone, dest_path\u003dNone):"},{"line_number":44,"context_line":"        \"\"\"Transfer image bits from Glance to the supplied destination."}],"source_content_type":"text/x-python","patch_set":6,"id":"7bd20f94_2a2aa4e0","line":41,"range":{"start_line":41,"start_character":22,"end_line":41,"end_character":46},"updated":"2026-11-05 18:11:12.000000000","message":"oh this s proably where the \"service terminoloty is coming form in hindsight\n\nwe may revsie this later but its fine for now","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"}],"cyborg/image/glance.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"54b6f22a3caaa1971ea82e0d11ebb4bbad85a288","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        for attempt in range(1, num_attempts + 1):"},{"line_number":85,"context_line":"            try:"},{"line_number":86,"context_line":"                return conn.image.download_image(image_id, stream\u003dTrue)"},{"line_number":87,"context_line":"            except sdk_exc.ForbiddenException:"},{"line_number":88,"context_line":"                raise exception.ImageNotAuthorized(image_id\u003dimage_id)"},{"line_number":89,"context_line":"            except sdk_exc.NotFoundException:"}],"source_content_type":"text/x-python","patch_set":2,"id":"a1e5218f_c9bf2ec0","line":86,"updated":"2026-10-31 01:22:56.000000000","message":"_download_data() maps openstacksdk exceptions to cyborg errors and retries 503, but Connection.image.download_image(image_id, stream\u003dTrue) does not raise for HTTP errors on the image data request. openstacksdk proxies request with raise_exc\u003dFalse and its DownloadMixin.download never validates the streamed /file response status; only the SDK\u0027s internal image-metadata fetch translates errors via raise_from_response. When the file GET fails while the metadata GET succeeds (deactivated image 403, transient worker 503), the error response is returned as a success and download() streams the error body into the destination file. The only status checked is \u003d\u003d 204.\n\n**Severity**: HIGH | **Confidence**: 0.85\n\n**Impact**: A Glance error response on the image data request is consumed as image data: agent/manager.py:fpga_program passes a corrupt .gbs bitstream to the driver\u0027s update(), which fails with an unrelated parse error instead of an image error. Transient 503s on the data request are silently swallowed instead of retried despite [glance] num_retries and the commit\u0027s stated contract, and 401/403/404/400 on the data request are not translated to ImageNotAuthorized/ResourceNotFound/ImageBadRequest.\n\n**Priority**: Before merge\n**Recommendation**:\nValidate the response inside the retry loop before returning it: call resp.raise_for_status() and translate requests.exceptions.HTTPError by e.response.status_code through the existing mapping (401/403 -\u003e ImageNotAuthorized, 404 -\u003e ResourceNotFound, 400 -\u003e ImageBadRequest, 503 -\u003e retry, otherwise GlanceConnectionFailed), or equivalently branch on resp.status_code \u003e\u003d 400 after download_image returns. Add a non-2xx-status test case (e.g., _mock_response(status_code\u003d403)) so the tests exercise the real SDK failure shape.","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"cb8f3be556f8cb900f22ddaf9df01e655592fcb8","unresolved":true,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        for attempt in range(1, num_attempts + 1):"},{"line_number":85,"context_line":"            try:"},{"line_number":86,"context_line":"                return conn.image.download_image(image_id, stream\u003dTrue)"},{"line_number":87,"context_line":"            except sdk_exc.ForbiddenException:"},{"line_number":88,"context_line":"                raise exception.ImageNotAuthorized(image_id\u003dimage_id)"},{"line_number":89,"context_line":"            except sdk_exc.NotFoundException:"}],"source_content_type":"text/x-python","patch_set":2,"id":"d9a8fc9a_650645ec","line":86,"in_reply_to":"a1e5218f_c9bf2ec0","updated":"2026-11-02 13:21:21.000000000","message":"i would have to revie the sdk code but it sound plausible.","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"3a9ec4930173a9d2d2438649640556ef5a976da0","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        for attempt in range(1, num_attempts + 1):"},{"line_number":85,"context_line":"            try:"},{"line_number":86,"context_line":"                return conn.image.download_image(image_id, stream\u003dTrue)"},{"line_number":87,"context_line":"            except sdk_exc.ForbiddenException:"},{"line_number":88,"context_line":"                raise exception.ImageNotAuthorized(image_id\u003dimage_id)"},{"line_number":89,"context_line":"            except sdk_exc.NotFoundException:"}],"source_content_type":"text/x-python","patch_set":2,"id":"0717df86_6b466515","line":86,"in_reply_to":"d9a8fc9a_650645ec","updated":"2026-11-02 20:36:23.000000000","message":"Done","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"cb8f3be556f8cb900f22ddaf9df01e655592fcb8","unresolved":true,"context_lines":[{"line_number":95,"context_line":"                raise exception.ImageBadRequest("},{"line_number":96,"context_line":"                    image_id\u003dimage_id, response\u003dstr(e)"},{"line_number":97,"context_line":"                )"},{"line_number":98,"context_line":"            except sdk_exc.HttpException as e:"},{"line_number":99,"context_line":"                status \u003d getattr(e, \u0027status_code\u0027, None)"},{"line_number":100,"context_line":"                if status \u003d\u003d 401:"},{"line_number":101,"context_line":"                    raise exception.ImageNotAuthorized(image_id\u003dimage_id)"},{"line_number":102,"context_line":"                if status \u003d\u003d 503 and attempt \u003c num_attempts:"},{"line_number":103,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":104,"context_line":"                    time.sleep(1)"},{"line_number":105,"context_line":"                    continue"},{"line_number":106,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":107,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":108,"context_line":"                )"},{"line_number":109,"context_line":"            except (sdk_exc.SDKException, ConnectionError) as e:"},{"line_number":110,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":111,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":112,"context_line":"                    time.sleep(1)"},{"line_number":113,"context_line":"                    continue"},{"line_number":114,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":115,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":116,"context_line":"                )"},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"    def download(self, context, image_id, data\u003dNone, dst_path\u003dNone):"},{"line_number":119,"context_line":"        \"\"\"Calls out to Glance for data and writes data.\"\"\""}],"source_content_type":"text/x-python","patch_set":2,"id":"65ba648f_f471a179","line":116,"range":{"start_line":98,"start_character":11,"end_line":116,"end_character":17},"updated":"2026-11-02 13:21:21.000000000","message":"```\nTraceback (most recent call last):\n  File \"/opt/stack/tempest/tempest/common/utils/__init__.py\", line 65, in wrapper\n    return f(*func_args, **func_kwargs)\n  File \"/opt/stack/tempest/.tox/tempest/lib/python3.13/site-packages/cyborg_tempest_plugin/tests/scenario/test_accelerator_basic_ops.py\", line 122, in test_fpga_program\n    program_response \u003d client.program_deployable(\n        deployables[0][\u0027uuid\u0027], self.image_create(name\u003d\u0027bitstream\u0027)\n    )\n  File \"/opt/stack/tempest/.tox/tempest/lib/python3.13/site-packages/cyborg_tempest_plugin/services/cyborg_rest_client.py\", line 178, in program_deployable\n    resp, body \u003d self.patch(url, body\u003dbody)\n                 ~~~~~~~~~~^^^^^^^^^^^^^^^^\n  File \"/opt/stack/tempest/tempest/lib/common/rest_client.py\", line 378, in patch\n    return self.request(\u0027PATCH\u0027, url, extra_headers, headers, body)\n           ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/stack/tempest/tempest/lib/common/rest_client.py\", line 767, in request\n    self._error_checker(resp, resp_body)\n    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^\n  File \"/opt/stack/tempest/tempest/lib/common/rest_client.py\", line 952, in _error_checker\n    raise exceptions.ServerFault(resp_body, resp\u003dresp,\n                                 message\u003dmessage)\ntempest.lib.exceptions.ServerFault: Got server fault\nDetails: b\u0027{\"error_message\": {\"faultcode\": \"Server\", \"faultstring\": \"Connection to glance host image service failed: The image service for :None exists but does not have any supported versions.\\\\nTraceback (most recent call last):\\\\n\\\\n  File \\\\\"/opt/stack/cyborg/cyborg/image/glance.py\\\\\", line 86, in _download_data\\\\n    return conn.image.download_image(image_id, stream\u003dTrue)\\\\n           ^^^^^^^^^^\\\\n\\\\n  File \\\\\"/opt/stack/data/venv/lib/python3.13/site-packages/openstack/service_description.py\\\\\", line 118, in __get__\\\\n    proxy \u003d self._make_proxy(instance)\\\\n\\\\n  File \\\\\"/opt/stack/data/venv/lib/python3.13/site-packages/openstack/service_description.py\\\\\", line 386, in _make_proxy\\\\n    raise exceptions.NotSupported(\\\\n    ...\u003c3 lines\u003e...\\\\n    )\\\\n\\\\nopenstack.exceptions.NotSupported: The image service for :None exists but does not have any supported versions.\\\\n\\\\n\\\\nDuring handling of the above exception, another exception occurred:\\\\n\\\\n\\\\nTraceback (most recent call last):\\\\n\\\\n  File \\\\\"/opt/stack/data/venv/lib/python3.13/site-packages/oslo_messaging/rpc/server.py\\\\\", line 176, in _process_incoming\\\\n    res \u003d self.dispatcher.dispatch(message)\\\\n\\\\n  File \\\\\"/opt/stack/data/venv/lib/python3.13/site-packages/oslo_messaging/rpc/dispatcher.py\\\\\", line 309, in dispatch\\\\n    return self._do_dispatch(endpoint, method, ctxt, args)\\\\n           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\\\n\\\\n  File \\\\\"/opt/stack/data/venv/lib/python3.13/site-packages/oslo_messaging/rpc/dispatcher.py\\\\\", line 229, in _do_dispatch\\\\n    result \u003d func(ctxt, **new_args)\\\\n\\\\n  File \\\\\"/opt/stack/cyborg/cyborg/agent/manager.py\\\\\", line 180, in fpga_program\\\\n    self.image_api.download(\\\\n    ~~~~~~~~~~~~~~~~~~~~~~~^\\\\n        context, bitstream_uuid, dest_path\u003ddownload_path.name\\\\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\\\n    )\\\\n    ^\\\\n\\\\n  File \\\\\"/opt/stack/cyborg/cyborg/image/api.py\\\\\", line 57, in download\\\\n    return session.download(\\\\n           ~~~~~~~~~~~~~~~~^\\\\n        context, image_id, data\u003ddata, dst_path\u003ddest_path\\\\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\\\n    )\\\\n    ^\\\\n\\\\n  File \\\\\"/opt/stack/cyborg/cyborg/image/glance.py\\\\\", line 120, in download\\\\n    resp \u003d self._download_data(context, image_id)\\\\n\\\\n  File \\\\\"/opt/stack/cyborg/cyborg/image/glance.py\\\\\", line 114, in _download_data\\\\n    raise exception.GlanceConnectionFailed(\\\\n        server\u003d\\\u0027image service\\\u0027, reason\u003dstr(e)\\\\n    )\\\\n\\\\ncyborg.common.exception.GlanceConnectionFailed: Connection to glance host image service failed: The image service for :None exists but does not have any supported versions.\\\\n\", \"debuginfo\": null}}\u0027\n```\nhttps://ba27e88a50b2ad7e63e5-76712d740ebbf703d38aaaff4a4082a6.ssl.cf1.rackcdn.com/openstack/309e118857a44253bc485243cb9765dd/testr_results.html\n\nthis implies oen of these fired.","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"3a9ec4930173a9d2d2438649640556ef5a976da0","unresolved":false,"context_lines":[{"line_number":95,"context_line":"                raise exception.ImageBadRequest("},{"line_number":96,"context_line":"                    image_id\u003dimage_id, response\u003dstr(e)"},{"line_number":97,"context_line":"                )"},{"line_number":98,"context_line":"            except sdk_exc.HttpException as e:"},{"line_number":99,"context_line":"                status \u003d getattr(e, \u0027status_code\u0027, None)"},{"line_number":100,"context_line":"                if status \u003d\u003d 401:"},{"line_number":101,"context_line":"                    raise exception.ImageNotAuthorized(image_id\u003dimage_id)"},{"line_number":102,"context_line":"                if status \u003d\u003d 503 and attempt \u003c num_attempts:"},{"line_number":103,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":104,"context_line":"                    time.sleep(1)"},{"line_number":105,"context_line":"                    continue"},{"line_number":106,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":107,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":108,"context_line":"                )"},{"line_number":109,"context_line":"            except (sdk_exc.SDKException, ConnectionError) as e:"},{"line_number":110,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":111,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":112,"context_line":"                    time.sleep(1)"},{"line_number":113,"context_line":"                    continue"},{"line_number":114,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":115,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":116,"context_line":"                )"},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"    def download(self, context, image_id, data\u003dNone, dst_path\u003dNone):"},{"line_number":119,"context_line":"        \"\"\"Calls out to Glance for data and writes data.\"\"\""}],"source_content_type":"text/x-python","patch_set":2,"id":"e5b2290a_09ac449e","line":116,"range":{"start_line":98,"start_character":11,"end_line":116,"end_character":17},"in_reply_to":"65ba648f_f471a179","updated":"2026-11-02 20:36:23.000000000","message":"Done","commit_id":"0ec294112084d208fcf74eb40819c4dfb258d081"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f6ed17df3c2cb2bf93d562c9f0c3200428064cb2","unresolved":false,"context_lines":[{"line_number":139,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":140,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":141,"context_line":"                )"},{"line_number":142,"context_line":"            except (sdk_exc.SDKException, ConnectionError) as e:"},{"line_number":143,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":144,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":145,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":3,"id":"8219ef72_03e6fa60","line":142,"updated":"2026-11-02 20:51:16.000000000","message":"The new retry handler uses Python\u0027s builtin ``ConnectionError``, but the download goes through openstacksdk/keystoneauth on top of ``requests``, whose transport failures surface as ``requests.exceptions.ConnectionError`` and ``requests.exceptions.Timeout``. Those subclass ``requests.exceptions.RequestException`` (i.e. ``IOError``), not the builtin ``ConnectionError``, and neither keystoneauth nor openstacksdk wraps transport-level failures into ``sdk_exc.SDKException``. Real transient failures (connection refused/reset, DNS failure, read timeout) therefore bypass the retry loop entirely and propagate uncaught instead of being converted to ``GlanceConnectionFailed``, contrary to both the code\u0027s stated retry contract and the commit message.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: With [glance] num_retries \u003e 0, transient Glance connectivity blips during FPGA bitstream download are not retried even though the change claims to keep that behavior, and callers receive a raw requests exception instead of cyborg\u0027s GlanceConnectionFailed, regressing the retry/error-conversion behavior the glanceclient implementation provided.\n\n**Suggestion**:\nCatch the requests exception hierarchy explicitly, e.g. ``from requests import exceptions as req_exc`` and ``except (sdk_exc.SDKException, req_exc.RequestException) as e:`` (this also covers timeouts), and change the unit test to raise ``req_exc.ConnectionError`` so the test exercises the real failure type.","commit_id":"1a4c3a1c3b278c353161605a567cc0ea4319b4c9"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f6ed17df3c2cb2bf93d562c9f0c3200428064cb2","unresolved":false,"context_lines":[{"line_number":167,"context_line":"                        image_id\u003dimage_id, response\u003d\u0027HTTP 400\u0027"},{"line_number":168,"context_line":"                    )"},{"line_number":169,"context_line":"                if status \u003d\u003d 503 and attempt \u003c num_attempts:"},{"line_number":170,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":171,"context_line":"                    time.sleep(1)"},{"line_number":172,"context_line":"                    continue"},{"line_number":173,"context_line":"                raise exception.GlanceConnectionFailed("}],"source_content_type":"text/x-python","patch_set":3,"id":"c75ac252_dff2a826","line":170,"updated":"2026-11-02 20:51:16.000000000","message":"In ``_download_data``, the HTTP-status branch retries on a 503 response by calling ``LOG.exception``, but no exception is in flight there — the SDK returned an error response without raising. ``LOG.exception`` reads ``sys.exc_info()``, which is empty in that context, so the log record will carry a meaningless \u0027NoneType: None\u0027 pseudo-traceback and no information about the actual HTTP status, producing misleading operator-facing output when debugging Glance availability.\n\n**Severity**: SUGGESTION | **Confidence**: 0.92\n\n**Impact**: Operator-facing logs for Glance 503 retries contain a spurious \u0027NoneType: None\u0027 traceback and omit the offending status code, adding noise and hiding the useful failure detail during incident diagnosis.\n\n**Recommendation**:\nUse ``LOG.error`` with the status in the message, e.g. ``LOG.error(\"Error contacting glance server (HTTP %s), retrying.\", status)``, and reserve LOG.exception for the except-based retry handlers.","commit_id":"1a4c3a1c3b278c353161605a567cc0ea4319b4c9"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f6ed17df3c2cb2bf93d562c9f0c3200428064cb2","unresolved":false,"context_lines":[{"line_number":232,"context_line":"    if \u0027/\u0027 not in str(image_href):"},{"line_number":233,"context_line":"        return get_default_image_service(), image_href"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    # Extract the image id (last path component) from the URL."},{"line_number":236,"context_line":"    image_id \u003d image_href.split(\u0027/\u0027)[-1]"},{"line_number":237,"context_line":"    return GlanceImageServiceV2(), image_id"},{"line_number":238,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"6b702b8b_aea9fa91","line":235,"updated":"2026-11-02 20:51:16.000000000","message":"``api.API._get_session_and_image_id``\u0027s docstring states that when ``id_or_uri`` is a URI, \u0027a client session connecting to the URI\u0027s image service endpoint will be returned\u0027. This change deletes endpoint extraction from image hrefs: ``get_remote_image_service`` now only splits the trailing UUID and always uses catalog-based discovery through the default service. The documented contract no longer exists, so the changed behavior contradicts the interface documentation left in place.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Impact**: Developers reading the image API layer will believe that passing an image URI targets that URI\u0027s Glance endpoint when it is silently ignored, a constraint concealed by the interface that invites misuse when debugging or extending image downloads.\n\n**Recommendation**:\nUpdate the ``_get_session_and_image_id`` docstring (cyborg/image/api.py:31-42) to state that only the image UUID is taken from a URI and the configured catalog endpoint is always used, keeping the documentation aligned with the new href handling.","commit_id":"1a4c3a1c3b278c353161605a567cc0ea4319b4c9"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3a85abe75176de2995954461f60ab470f5938f23","unresolved":false,"context_lines":[{"line_number":141,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":142,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":143,"context_line":"                )"},{"line_number":144,"context_line":"            except (sdk_exc.SDKException, req_exc.RequestException) as e:"},{"line_number":145,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":146,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":147,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":5,"id":"15d85e87_620901b8","line":144,"updated":"2026-11-02 23:18:26.000000000","message":"_download_data retries and wraps only openstacksdk SDKException and requests RequestException. The SDK image download goes through keystoneauth, whose Session.request converts requests connection errors into keystoneauth exceptions (ConnectFailure for connection errors, plus ConnectTimeout and SSLError), all deriving from keystoneauth\u0027s ClientException and not from SDKException or requests.RequestException. The dominant transport failure modes (Glance unreachable, connect timeout) therefore fall through both clauses uncaught.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: With [glance] num_retries set, an image download against an unreachable Glance endpoint is not retried and raises a raw keystoneauth exception instead of GlanceConnectionFailed. The sole caller (cyborg/agent/manager.py fpga_program) propagates it through RPC, so operators see an unfamiliar keystoneauth traceback and the configured retry knob silently does not apply to the most common outage mode.\n\n**Suggestion**:\nAdd keystoneauth connection exceptions to the retryable tuple in _download_data, e.g. catch keystoneauth1.exceptions.connection.ConnectFailure (covers ConnectTimeout/MaxRetriesExceeded) and SSLError so they retry and end in GlanceConnectionFailed; also update test_download_retries_on_connection_error to raise the keystoneauth type the real path produces.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1d1123b184012d6e31ccafda1dc0677a6ab66c65","unresolved":true,"context_lines":[{"line_number":141,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":142,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":143,"context_line":"                )"},{"line_number":144,"context_line":"            except (sdk_exc.SDKException, req_exc.RequestException) as e:"},{"line_number":145,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":146,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":147,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":5,"id":"9eff802f_93812af8","line":144,"in_reply_to":"15d85e87_620901b8","updated":"2026-11-03 01:24:28.000000000","message":"i have not had time to review this properly so im not sure if this is valid.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"956e232bca7c5417b28d9e8b47e9496400fe0b44","unresolved":true,"context_lines":[{"line_number":141,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":142,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":143,"context_line":"                )"},{"line_number":144,"context_line":"            except (sdk_exc.SDKException, req_exc.RequestException) as e:"},{"line_number":145,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":146,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":147,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":5,"id":"e148aa80_10eb17b2","line":144,"in_reply_to":"9eff802f_93812af8","updated":"2026-11-03 18:08:28.000000000","message":"Looks like it is valid, will need to fix.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"e4b3e9797b3c1e441f3111a548eeb9e5cc221a8d","unresolved":false,"context_lines":[{"line_number":141,"context_line":"                raise exception.GlanceConnectionFailed("},{"line_number":142,"context_line":"                    server\u003d\u0027image service\u0027, reason\u003dstr(e)"},{"line_number":143,"context_line":"                )"},{"line_number":144,"context_line":"            except (sdk_exc.SDKException, req_exc.RequestException) as e:"},{"line_number":145,"context_line":"                if attempt \u003c num_attempts:"},{"line_number":146,"context_line":"                    LOG.exception(\"Error contacting glance server, retrying.\")"},{"line_number":147,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":5,"id":"77eb4812_e4f2a17d","line":144,"in_reply_to":"e148aa80_10eb17b2","updated":"2026-11-03 18:12:40.000000000","message":"Done","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"7032a4c294b9c81a61716fa5b3e7f176278c9e01","unresolved":true,"context_lines":[{"line_number":202,"context_line":"            return resp"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        try:"},{"line_number":205,"context_line":"            for chunk in resp.iter_content(chunk_size\u003d1024 * 1024):"},{"line_number":206,"context_line":"                data.write(chunk)"},{"line_number":207,"context_line":"        except Exception as ex:"},{"line_number":208,"context_line":"            with excutils.save_and_reraise_exception():"},{"line_number":209,"context_line":"                LOG.error("},{"line_number":210,"context_line":"                    \"Error writing to %(path)s: %(exception)s\","},{"line_number":211,"context_line":"                    {\u0027path\u0027: dst_path, \u0027exception\u0027: ex},"},{"line_number":212,"context_line":"                )"},{"line_number":213,"context_line":"        finally:"},{"line_number":214,"context_line":"            if close_file:"}],"source_content_type":"text/x-python","patch_set":5,"id":"00ec8194_5546190b","line":211,"range":{"start_line":205,"start_character":11,"end_line":211,"end_character":56},"updated":"2026-11-03 10:58:43.000000000","message":"I was checking the openstacksdk download_image code https://github.com/openstack/openstacksdk/blob/8e758b8ee81375ca40fc55c115c793b830bc864c/openstack/image/v2/_proxy.py#L919\n```\ndef download_image(\n        self,\n        image: str | _image.Image,\n        *,\n        stream: bool \u003d False,\n        output: str | io.IOBase | None \u003d None,\n        chunk_size: int \u003d 1024 * 1024,\n        store_preferences: Sequence[str] | None \u003d None,\n    ) -\u003e requests.Response:\n```\ndownload_image has option to pass the dst_path as output params as well as chunk_size.\n\n\nIs it possible to directly use the download_image method here and drop these additional code which openstacksdk glance download_images takes care of that.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"956e232bca7c5417b28d9e8b47e9496400fe0b44","unresolved":true,"context_lines":[{"line_number":202,"context_line":"            return resp"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        try:"},{"line_number":205,"context_line":"            for chunk in resp.iter_content(chunk_size\u003d1024 * 1024):"},{"line_number":206,"context_line":"                data.write(chunk)"},{"line_number":207,"context_line":"        except Exception as ex:"},{"line_number":208,"context_line":"            with excutils.save_and_reraise_exception():"},{"line_number":209,"context_line":"                LOG.error("},{"line_number":210,"context_line":"                    \"Error writing to %(path)s: %(exception)s\","},{"line_number":211,"context_line":"                    {\u0027path\u0027: dst_path, \u0027exception\u0027: ex},"},{"line_number":212,"context_line":"                )"},{"line_number":213,"context_line":"        finally:"},{"line_number":214,"context_line":"            if close_file:"}],"source_content_type":"text/x-python","patch_set":5,"id":"2aa7cf69_24fcba3c","line":211,"range":{"start_line":205,"start_character":11,"end_line":211,"end_character":56},"in_reply_to":"00ec8194_5546190b","updated":"2026-11-03 18:08:28.000000000","message":"Thanks for pointing this out. As far as I can tell, we could use it but the main difference is we would lose the data flush() and fsync we currently have here (but would gain checksum validation). \n\nWe could consider proposing a change to SDK to add a flush/fsync flag and then use it after the next release. The Nova code also uses fsync [1], so they could also potentially use it if/when they switch to SDK.\n\n[1] https://github.com/openstack/nova/blob/b82fedba6be128b2b8570346c8f09301256edfbd/nova/image/glance.py#L456","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"da364b0d5365025db28ea201724705386991d676","unresolved":false,"context_lines":[{"line_number":202,"context_line":"            return resp"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        try:"},{"line_number":205,"context_line":"            for chunk in resp.iter_content(chunk_size\u003d1024 * 1024):"},{"line_number":206,"context_line":"                data.write(chunk)"},{"line_number":207,"context_line":"        except Exception as ex:"},{"line_number":208,"context_line":"            with excutils.save_and_reraise_exception():"},{"line_number":209,"context_line":"                LOG.error("},{"line_number":210,"context_line":"                    \"Error writing to %(path)s: %(exception)s\","},{"line_number":211,"context_line":"                    {\u0027path\u0027: dst_path, \u0027exception\u0027: ex},"},{"line_number":212,"context_line":"                )"},{"line_number":213,"context_line":"        finally:"},{"line_number":214,"context_line":"            if close_file:"}],"source_content_type":"text/x-python","patch_set":5,"id":"8a62276c_8ef58b02","line":211,"range":{"start_line":205,"start_character":11,"end_line":211,"end_character":56},"in_reply_to":"2aa7cf69_24fcba3c","updated":"2026-11-04 05:36:24.000000000","message":"Yes, correct, flush functionality is missing in openstacksdk.  Sounds good to add this in this openstacksdk in future.\n\nglanceclient code was copied from nova itself when program support was getting added here.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"ad85db0c9f08bb2710a56aa57bc3eb5065fa764b","unresolved":false,"context_lines":[{"line_number":202,"context_line":"            return resp"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        try:"},{"line_number":205,"context_line":"            for chunk in resp.iter_content(chunk_size\u003d1024 * 1024):"},{"line_number":206,"context_line":"                data.write(chunk)"},{"line_number":207,"context_line":"        except Exception as ex:"},{"line_number":208,"context_line":"            with excutils.save_and_reraise_exception():"},{"line_number":209,"context_line":"                LOG.error("},{"line_number":210,"context_line":"                    \"Error writing to %(path)s: %(exception)s\","},{"line_number":211,"context_line":"                    {\u0027path\u0027: dst_path, \u0027exception\u0027: ex},"},{"line_number":212,"context_line":"                )"},{"line_number":213,"context_line":"        finally:"},{"line_number":214,"context_line":"            if close_file:"}],"source_content_type":"text/x-python","patch_set":5,"id":"c1e06d2a_81b8310b","line":211,"range":{"start_line":205,"start_character":11,"end_line":211,"end_character":56},"in_reply_to":"8a62276c_8ef58b02","updated":"2026-11-04 14:17:09.000000000","message":"hum i tought that when you used `with open(paht,\u0027wb\u0027):` as a context manager it auto closed and flused the content to disk when you exited the context manger\n\nhttps://github.com/openstack/openstacksdk/blob/master/openstack/image/_download.py#L161-L165\n\nso i dont think we are missing the flush but we proably are missing an explcit fsync\n\nunlike nova we do not expect to be using nfs but i think im fine with mirrior this logic for nova for now and we can perhasp optimise it more later","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"56a52eea7216be58dafffd1ee86e87ce193c119f","unresolved":false,"context_lines":[{"line_number":53,"context_line":""},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"def _get_connection(context):"},{"line_number":56,"context_line":"    \"\"\"Create an openstacksdk Connection to the image service."},{"line_number":57,"context_line":""},{"line_number":58,"context_line":"    Endpoint discovery is done via a keystoneauth Adapter so that ``[glance]``"},{"line_number":59,"context_line":"    config options (``endpoint_override``, ``valid_interfaces``) are respected"}],"source_content_type":"text/x-python","patch_set":6,"id":"0a9e30d0_c925980a","line":56,"range":{"start_line":56,"start_character":48,"end_line":56,"end_character":62},"updated":"2026-11-05 18:11:12.000000000","message":"aka glance","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"}],"releasenotes/notes/replace-glanceclient-with-sdk-a3b7c9d1e5f20846.yaml":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3a85abe75176de2995954461f60ab470f5938f23","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"upgrade:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The ``python-glanceclient`` dependency has been replaced by"},{"line_number":5,"context_line":"    ``openstacksdk`` for all Glance image service operations.  ``openstacksdk``"},{"line_number":6,"context_line":"    was already a dependency so no new packages are required. The ``[glance]``"}],"source_content_type":"text/x-yaml","patch_set":5,"id":"ce09c66e_1b097b96","line":3,"updated":"2026-11-02 23:18:26.000000000","message":"requirements.txt raises openstacksdk from \u003e\u003d0.46.0 to \u003e\u003d1.0.0, but the new upgrade release note only states that python-glanceclient was replaced and that openstacksdk \u0027was already a dependency so no new packages are required\u0027. The floor raise is not mentioned even though it is the upgrade-relevant part: deployments whose environments resolve an older openstacksdk must upgrade it before the new code (which imports ForbiddenException) will run.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: Operators planning upgrades read release notes, not commit messages; a deployment whose environment resolves openstacksdk \u003c 1.0.0 (distro package or shared constraints) will fail on the missing ForbiddenException after upgrading cyborg, with no upgrade-note hint that the SDK floor moved.\n\n**Suggestion**:\nAdd a sentence to the upgrade note stating the openstacksdk minimum version was raised to \u003e\u003d1.0.0 (needed for openstack.exceptions.ForbiddenException) and that deployments must have at least that version installed.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1d1123b184012d6e31ccafda1dc0677a6ab66c65","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"upgrade:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The ``python-glanceclient`` dependency has been replaced by"},{"line_number":5,"context_line":"    ``openstacksdk`` for all Glance image service operations.  ``openstacksdk``"},{"line_number":6,"context_line":"    was already a dependency so no new packages are required. The ``[glance]``"}],"source_content_type":"text/x-yaml","patch_set":5,"id":"c6dd93d3_c069a308","line":3,"in_reply_to":"ce09c66e_1b097b96","updated":"2026-11-03 01:24:28.000000000","message":"the current uc and latest release fo the sdk is 4.22.0\n\nhttps://github.com/openstack/requirements/blob/master/upper-constraints.txt#L457\n\n1.0 is anchent and we dont need to specyify the exact min verison\n\n\nwe likely could/should actully set our requrieemtn to someting like \u003e\u003d4.0.0 but we dont need to specify that here.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f42ce0ddea775e02704cdd2b9e0a196cf370ef3c","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"upgrade:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The ``python-glanceclient`` dependency has been replaced by"},{"line_number":5,"context_line":"    ``openstacksdk`` for all Glance image service operations. ``openstacksdk``"},{"line_number":6,"context_line":"    was already a dependency so no new packages are required. The ``[glance]``"}],"source_content_type":"text/x-yaml","patch_set":6,"id":"2eb81e74_a58298f2","line":3,"updated":"2026-11-03 18:28:53.000000000","message":"The upgrade note states that openstacksdk \u0027was already a dependency so no new packages are required\u0027, which reads as dependency-neutral, while the same change raises the declared openstacksdk minimum in requirements.txt from \u003e\u003d0.46.0 to \u003e\u003d4.0.0. Environments running openstacksdk between 0.46.0 and 3.x satisfy the old requirement but fail the new floor, so installing or upgrading this cyborg version there forces an openstacksdk major-version upgrade (major versions 1.x through 4.x each removed deprecated APIs and older Python support). An upgrade note is the operator-facing document for exactly this kind of compatibility impact, and it is the only dependency statement many operators read when planning the upgrade.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Operators upgrading cyborg in environments with older openstacksdk (which satisfied the previous \u003e\u003d0.46.0 floor) will encounter pip dependency-resolution failures or an unplanned openstacksdk major upgrade that the upgrade note does not warn about, complicating upgrade planning and validation for deployments that do not track coordinated OpenStack upper-constraints.\n\n**Suggestion**:\nExtend the upgrade note to disclose the floor raise, e.g. append: \u0027The minimum ``openstacksdk`` version is raised from 0.46.0 to 4.0.0; deployments must have openstacksdk 4.0.0 or newer installed (python-glanceclient is no longer required).\u0027","commit_id":"79498b1edbf25605c8162d18f8862808ce51523b"}],"requirements.txt":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"2237c3d70519bf1007d05ced1b6938a15d5a3c5e","unresolved":false,"context_lines":[{"line_number":29,"context_line":"jsonpatch\u003e\u003d1.16,!\u003d1.20 # BSD"},{"line_number":30,"context_line":"psutil\u003e\u003d3.2.2 # BSD"},{"line_number":31,"context_line":"oslo.privsep\u003e\u003d1.32.0 # Apache-2.0"},{"line_number":32,"context_line":"openstacksdk\u003e\u003d0.46.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":4,"id":"d35e4f23_3f7b3ccb","line":32,"updated":"2026-11-02 21:17:12.000000000","message":"The change keeps the openstacksdk floor at \u003e\u003d0.46.0 (requirements.txt:32) while adopting APIs that do not exist at that version. cyborg/image/glance.py:87 calls connection.Connection(...).global_request(context.global_id); in openstacksdk 0.46.0-0.99.x, Connection only has set_global_request_id (verified in the published 0.46.0 and 0.99.0 wheels); Connection.global_request first exists in 1.0.0 via _OpenStackCloudMixin. glance.py:124 catches sdk_exc.NotFoundException, which was only added in openstacksdk 4.0.0 (1.0.0-3.3.0 only provide ResourceNotFound; 0.46.0 has neither NotFoundException nor ForbiddenException). As a result, on any openstacksdk release in [0.46.0, 4.0.0), which satisfies the declared requirement, every image download raises AttributeError and fails.\n\n**Severity**: HIGH | **Confidence**: 0.95\n\n**Impact**: Deployments that resolve openstacksdk per the declared floor (for example packaging builds or environments pinned to older SDK releases) get AttributeError: \u0027Connection\u0027 object has no attribute \u0027global_request\u0027 on every Glance download, so FPGA bitstream download and programming via the agent manager\u0027s fpga_program() fails entirely. CI/devstack installs using upper constraints resolve a current SDK and will not surface this, which is why the gate stays green.\n\n**Priority**: Before merge\n**Recommendation**:\nRaise the requirements.txt floor to openstacksdk\u003e\u003d4.0.0, which is the first release providing NotFoundException (and therefore also ForbiddenException and Connection.global_request), matching the API set the new code requires; optionally add a comment noting the floor follows the Ironic image_service pattern. Reverting to ResourceNotFound/set_global_request_id to preserve the 0.46.0 floor is not practical because ResourceNotFound was removed in 4.x.","commit_id":"a09c931e10f97f6104f1bccc5f6f941007203d24"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"1d1123b184012d6e31ccafda1dc0677a6ab66c65","unresolved":true,"context_lines":[{"line_number":29,"context_line":"jsonpatch\u003e\u003d1.16,!\u003d1.20 # BSD"},{"line_number":30,"context_line":"psutil\u003e\u003d3.2.2 # BSD"},{"line_number":31,"context_line":"oslo.privsep\u003e\u003d1.32.0 # Apache-2.0"},{"line_number":32,"context_line":"openstacksdk\u003e\u003d1.0.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":5,"id":"6095fd42_81bf2509","line":32,"updated":"2026-11-03 01:24:28.000000000","message":"realisticlly im sure we could be usign stuff form later version implictly\n\nshall we just bump this to the current major verson of 4.0.0?\n4.0.0 was released on Sep 2, 2024 so part of the 2024.2 release\n\nthat is already un unmainatined at this point so i think usign 4.0.0 as our baselien woudl be prettey safe.\n\n1.0.0 was Jan 31, 2023 so antelope and which had a min python of 3.8 and make of 3.10 in the testign runtimes\n\nhttps://opendev.org/openstack/governance/src/branch/master/reference/runtimes/2023.1.rst?display\u003dsource#L42\n\n\nour min python is now 3.11 so 1.0.0 is unlikely to actully work with master","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"956e232bca7c5417b28d9e8b47e9496400fe0b44","unresolved":true,"context_lines":[{"line_number":29,"context_line":"jsonpatch\u003e\u003d1.16,!\u003d1.20 # BSD"},{"line_number":30,"context_line":"psutil\u003e\u003d3.2.2 # BSD"},{"line_number":31,"context_line":"oslo.privsep\u003e\u003d1.32.0 # Apache-2.0"},{"line_number":32,"context_line":"openstacksdk\u003e\u003d1.0.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":5,"id":"a439029c_8605347b","line":32,"in_reply_to":"6095fd42_81bf2509","updated":"2026-11-03 18:08:28.000000000","message":"Yeah, I thought similar but couldn\u0027t decide what version to use. 4.0.0 sounds reasonable to me.","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"e4b3e9797b3c1e441f3111a548eeb9e5cc221a8d","unresolved":false,"context_lines":[{"line_number":29,"context_line":"jsonpatch\u003e\u003d1.16,!\u003d1.20 # BSD"},{"line_number":30,"context_line":"psutil\u003e\u003d3.2.2 # BSD"},{"line_number":31,"context_line":"oslo.privsep\u003e\u003d1.32.0 # Apache-2.0"},{"line_number":32,"context_line":"openstacksdk\u003e\u003d1.0.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":5,"id":"d3575da5_79d12c9b","line":32,"in_reply_to":"a439029c_8605347b","updated":"2026-11-03 18:12:40.000000000","message":"Done","commit_id":"bb55895660a22e18408f3f6b276c73d8be645b7a"}]}
