diff -pruN 4.9.1-2/.gitignore 5.0.0-0ubuntu2/.gitignore
--- 4.9.1-2/.gitignore	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/.gitignore	1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-*~
-*.pyc
-*.dat
-TAGS
-*.egg-info
-*.egg
-.eggs/*
-build
-.coverage
-.tox
-.stestr
-cover
-venv
-.venv
-output.xml
-*.sublime-workspace
-*.sqlite
-*.html
-.*.swp
-.DS_Store
-.testrepository
-versioninfo
-var/*
-ChangeLog
-AUTHORS
-subunit.log
-covhtml/
-doc/source/reference/api
-
-# Files created by releasenotes build
-releasenotes/build
-
-#Files created by functional tests
-functional_testing.conf
diff -pruN 4.9.1-2/.gitreview 5.0.0-0ubuntu2/.gitreview
--- 4.9.1-2/.gitreview	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/.gitreview	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-[gerrit]
-host=review.opendev.org
-port=29418
-project=openstack/glance_store.git
diff -pruN 4.9.1-2/.zuul.yaml 5.0.0-0ubuntu2/.zuul.yaml
--- 4.9.1-2/.zuul.yaml	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/.zuul.yaml	2025-07-10 09:13:16.000000000 +0000
@@ -124,6 +124,11 @@
     timeout: 10800
     vars:
       tempest_test_regex: (^tempest\.(api|scenario)|(^cinder_tempest_plugin))
+      devstack_local_conf:
+        post-config:
+          $GLANCE_API_CONF:
+            DEFAULT:
+              do_secure_hash: False
 
 - job:
     name: cross-glance-tox-functional
diff -pruN 4.9.1-2/AUTHORS 5.0.0-0ubuntu2/AUTHORS
--- 4.9.1-2/AUTHORS	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/AUTHORS	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,171 @@
+Abhijeet Malawade <Abhijeet.Malawade@nttdata.com>
+Abhishek Kekane <akekane@redhat.com>
+Adam Kijak <adam.kijak@corp.ovh.com>
+Adam Zhang <adamz@vmware.com>
+Ade Lee <alee@redhat.com>
+Akihiro Motoki <amotoki@gmail.com>
+Alexandre Arents <alexandre.arents@corp.ovh.com>
+Alfredo Moralejo <amoralej@redhat.com>
+Andrea Rosa <andrea.rosa@hp.com>
+Andreas Jaeger <aj@suse.com>
+Andreas Jaeger <aj@suse.de>
+Andrew Bogott <abogott@wikimedia.org>
+Andrey Pavlov <andrey-mp@yandex.ru>
+Andrey Pavlov <andrey.mp@gmail.com>
+Andrii Ostapenko <aostapenko@mirantis.com>
+Ankit Agrawal <ankit11.agrawal@nttdata.com>
+Arnaud Legendre <arnaudleg@gmail.com>
+Arnaud Morin <arnaud.morin@ovhcloud.com>
+Ben Roble <ben.roble@rackspace.com>
+Brian D. Elliott <bdelliott@gmail.com>
+Brian Rosmaita <brian.rosmaita@rackspace.com>
+Brian Rosmaita <rosmaita.fossdev@gmail.com>
+Brianna Poulos <Brianna.Poulos@jhuapl.edu>
+Cao Xuan Hoang <hoangcx@vn.fujitsu.com>
+ChangBo Guo(gcb) <eric.guo@easystack.cn>
+Christian Rohmann <christian.rohmann@inovex.de>
+Christian Schwede <cschwede@redhat.com>
+Chuck Short <chucks@redhat.com>
+Cindy Pallares <cindy.pallaresq@gmail.com>
+Corey Bryant <corey.bryant@canonical.com>
+Cyril Roelandt <cyril@redhat.com>
+Dan Prince <dprince@redhat.com>
+Dan Smith <dansmith@redhat.com>
+Dan Smith <dms@danplanet.com>
+Danny Al-Gaaf <danny.al-gaaf@bisect.de>
+Darja Malyavkina <dshakhray@mirantis.com>
+Dharini Chandrasekar <dharini.chandrasekar@intel.com>
+Doug Hellmann <doug@doughellmann.com>
+Dr. Jens Harbott <harbott@osism.tech>
+Drew Varner <avarner@linux.vnet.ibm.com>
+Edgar Magana <emagana@gmail.com>
+Elancheran T.S <tsecheran@yahoo.com>
+Eric Brown <browne@vmware.com>
+Eric Harney <eharney@redhat.com>
+Erno Kuvaja <jokke@hp.com>
+Erno Kuvaja <jokke@usr.fi>
+Flavio Percoco <flaper87@gmail.com>
+Ghanshyam Mann <gmann@ghanshyammann.com>
+Giridhar Jayavelu <gjayavelu@vmware.com>
+Gorka Eguileor <geguileo@redhat.com>
+Haikel Guemar <hguemar@fedoraproject.org>
+Hemanth Makkapati <hemanth.makkapati@rackspace.com>
+Hervé Beraud <hberaud@redhat.com>
+Hoang Trung Hieu <hieuht@vn.fujitsu.com>
+Ian Cordasco <graffatcolmingov@gmail.com>
+Ian Cordasco <ian.cordasco@rackspace.com>
+Ian Cordasco <sigmavirus24@gmail.com>
+Itisha Dewan <ishadewan07@gmail.com>
+Jake Yip <jake.yip@unimelb.edu.au>
+James Page <james.page@ubuntu.com>
+Jamie Lennox <jamielennox@gmail.com>
+Jamie Lennox <jamielennox@redhat.com>
+Jens Rosenboom <j.rosenboom@x-ion.de>
+Jeremy Stanley <fungi@yuggoth.org>
+Jesse J. Cook <jesse.cook@rackspace.com>
+Jian Wen <wenjian@letv.com>
+JordanP <jordan.pittier@scality.com>
+Josh Durgin <josh.durgin@inktank.com>
+Jun Hong Li <junhongl@cn.ibm.com>
+Kairat Kushaev <kkushaev@mirantis.com>
+LeopardMa <mabao@inspur.com>
+Li Wei <wei.li@easystack.cn>
+Liang Fang <liang.a.fang@intel.com>
+LiuNanke <nanke.liu@easystack.cn>
+Louis Taylor <kragniz@gmail.com>
+Louis Taylor <louis@kragniz.eu>
+Lucian Petrut <lpetrut@cloudbasesolutions.com>
+Luigi Toscano <ltoscano@redhat.com>
+Masashi Ozawa <mozawa@cloudian.com>
+Matt Riedemann <mriedem@us.ibm.com>
+Matt Smith <mss@datera.io>
+Michal Arbet <michal.arbet@ultimum.io>
+Mike Durnosvystov <glacierr.dev@gmail.com>
+Mike Fedosin <mfedosin@mirantis.com>
+Mingda Sun <mingda@unitedstack.com>
+Mohammed Naser <mnaser@vexxhost.com>
+Naohiro Sameshima <naohiro.sameshima@global.ntt>
+Nguyen Hai <nguyentrihai93@gmail.com>
+Nguyen Hung Phuong <phuongnh@vn.fujitsu.com>
+Niall Bunting <niall.bunting@hpe.com>
+NiallBunting <niall.bunting@hp.com>
+Nikhil Komawar <nik.komawar@gmail.com>
+Nikhil Komawar <nikhilskomawar@gmail.com>
+Nina Goradia <ninag@us.ibm.com>
+Nobuto Murata <nobuto.murata@canonical.com>
+Oleksii Chuprykov <ochuprykov@mirantis.com>
+Ondřej Nový <ondrej.novy@firma.seznam.cz>
+OpenStack Release Bot <infra-root@openstack.org>
+Paul Belanger <pabelanger@redhat.com>
+Pavlo Shchelokovskyy <shchelokovskyy@gmail.com>
+Pranali Deore <pdeore@redhat.com>
+Radoslaw Smigielski <radoslaw.smigielski@alcatel-lucent.com>
+Rajat Dhasmana <rajatdhasmana@gmail.com>
+Rajesh Tailor <rajesh.tailor@nttdata.com>
+Ronald Bradford <ronald.bradford@gmail.com>
+RustShen <rustinpeace@163.com>
+Sabari Kumar Murugesan <smurugesan@vmware.com>
+Scott McClymont <scott.mcclymont@verizonwireless.com>
+Sean McGinnis <sean.mcginnis@gmail.com>
+Sean McGinnis <sean.mcginnis@huawei.com>
+Shuquan Huang <huang.shuquan@99cloud.net>
+Stefan Dinescu <stefan.dinescu@windriver.com>
+Stephen Finucane <stephenfin@redhat.com>
+Stuart McLaren <stuart.mclaren@hp.com>
+Stuart McLaren <stuart.​mclaren@hp.​com>
+Szymon Datko <szymon.datko@corp.ovh.com>
+Sławek Kapłoński <slawek@kaplonski.pl>
+THOMAS J. COCOZZELLO <tjcocozz@us.ibm.com>
+Takashi Kajinami <kajinamit@oss.nttdata.com>
+Takashi Kajinami <tkajinam@redhat.com>
+Takashi Natsume <takanattie@gmail.com>
+Taylor Peoples <tpeoples@us.ibm.com>
+Thomas Bechtold <tbechtold@suse.com>
+Tim Burke <tim.burke@gmail.com>
+Tom Cocozzello <tjcocozz@us.ibm.com>
+Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
+Tomoki Sekiyama <tomoki.sekiyama@gmail.com>
+Tony Breeds <tony@bakeyournoodle.com>
+Victor Coutellier <victor.coutellier@gmail.com>
+Victor Sergeyev <vsergeyev@mirantis.com>
+Victor Stinner <vstinner@redhat.com>
+Vikhyat Umrao <vumrao@redhat.com>
+Vincent Untz <vuntz@suse.com>
+Vladislav Kuzmin <vkuzmin@mirantis.com>
+Weijin Wang <wiwang@vmware.com>
+XiaojueGuan <guanalbertjone@gmail.com>
+Xinxin Shen <shenxinxin@inspur.com>
+XinxinShen <shenxinxin@inspur.com>
+YAMADA Hideki <yamada.hideki@lab.ntt.co.jp>
+Yu Shengzuo <yu.shengzuo@99cloud.net>
+Zhi Yan Liu <zhiyanl@cn.ibm.com>
+Zoltan Arnold Nagy <nag@zurich.ibm.com>
+anguoming <agm_daydayup@foxmail.com>
+ankitagrawal <ankit11.agrawal@nttdata.com>
+asmita singh <asmita.singh@nttdata.com>
+caoyuan <cao.yuan@99cloud.net>
+chenjiao <chenjiao@inspur.com>
+gengchc2 <geng.changcai2@zte.com.cn>
+hgangwx@cn.ibm.com <hgangwx@cn.ibm.com>
+kairat_kushaev <kkushaev@mirantis.com>
+khashf <6059347+khashf@users.noreply.github.com>
+liuyamin <liuyamin@fiberhome.com>
+liyou01 <liyou01@inspur.com>
+lujie <lujie@ict.ac.cn>
+luqitao <qtlu@fiberhome.com>
+ricolin <rico.lin@easystack.cn>
+skseeker <er.sksumit@gmail.com>
+song jian <jian.song@easystack.cn>
+wangxiyuan <wangxiyuan1007@gmail.com>
+whoami-rajat <rajatdhasmana@gmail.com>
+wu.chunyang <wuchunyang@yovole.com>
+xuanyandong <xuanyandong@inspur.com>
+yanghuichan <yanghc@fiberhome.com>
+yfzhao <dsware@126.com>
+yuyafei <yu.yafei@zte.com.cn>
+zhangbailin <zhangbailin@inspur.com>
+zhangboye <zhangboye@inspur.com>
+zhangdaolong <zhangdaolong@fiberhome.com>
+zhangsong <zhangsong@cmss.chinamobile.com>
+zhengyao1 <zheng.yao1@zte.com.cn>
+zhufl <zhu.fanglei@zte.com.cn>
diff -pruN 4.9.1-2/ChangeLog 5.0.0-0ubuntu2/ChangeLog
--- 4.9.1-2/ChangeLog	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/ChangeLog	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,1044 @@
+CHANGES
+=======
+
+5.0.0
+-----
+
+* Replace assertIn with assertRaisesRegex
+* swift: Drop support for v1/v2 auth
+* Replace os-client-config
+* [cinder] Add size validation for image uploads
+* [rbd] Add size validation for image uploads
+* [swift] Add size validation for image uploads
+* [filesystem] Add size validation for image uploads
+* [s3] Add size validation for image uploads
+* Add support for backend\_defaults group
+* Deprecate filesystem\_store\_datadirs
+* Drop explicit dependency on python-subunit
+* Remove Python 3.9 support
+
+4.10.0
+------
+
+* Replace Eventlet with concurrent.futures
+* Disable do\_secure\_hash for glance\_store-src-ceph-tempest
+* VMware: Refactor config options
+* Filesystem: Refactor config options
+* RBD: Refactor config options
+* Update master for stable/2025.1
+* Imported Translations from Zanata
+
+4.9.1
+-----
+
+* Imported Translations from Zanata
+
+4.9.0
+-----
+
+* Update python classifier as per the 2025.1 cycle testing runtime
+* Move Ubuntu focal jobs to Ubuntu Jammy
+* Followup: Add try/finally block
+* Add interface to get store weight from memory
+* Imported Translations from Zanata
+* Cinder PowerFlex: Fix issue when downloading image
+* S3: add option to specify a custom CA cert bundle
+* Add note about requirements lower bounds
+* Use time.sleep() instead of eventlet.sleep()
+* Follow-up of "Move to python3.9 as minimal python version"
+* Move to python3.9 as minimal python version
+* Update master for stable/2024.2
+
+4.8.1
+-----
+
+* Imported Translations from Zanata
+* reno: Update master for unmaintained/zed
+
+4.8.0
+-----
+
+* Update status of VMWare store driver
+* Update maintainer of rbd driver and cinder driver
+* Use normal credentials for legacy image update
+* reno: Update master for xena Unmaintained status
+* reno: Update master for wallaby Unmaintained status
+* reno: Update master for victoria Unmaintained status
+* Update master for stable/2024.1
+
+4.7.0
+-----
+
+* reno: Update master for yoga Unmaintained status
+* Remove \_snapshot\_has\_external\_reference from rbd driver
+* Bump hacking
+* s3: Do not log access keys
+* Do not show access\_key in s3 driver
+* RBD: Use rados\_connect\_timeout to override timeout
+* rbd: compute appropriate resize amount before resizing image
+* Update python classifier in setup.cfg
+* Remove unnecessary ceilometer service overrides
+* Increase timeout of glance\_store-src-ceph-tempest
+* Remove unused httplib2
+* Remove unused test tools
+* cinder: Catch missing dependencies
+* Update master for stable/2023.2
+* Deprecate VMWare Datastore
+
+4.6.1
+-----
+
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+
+4.6.0
+-----
+
+* RBD: Trash image when snapshots prevent deletion
+* Add per-store weight config element
+* RBD: Wrap RBD calls in native threads
+* Make ceph job voting
+
+4.5.0
+-----
+
+* Revert "RBD: Wrap RBD calls in native threads"
+* Update 'extras' for cinder driver
+* Imported Translations from Zanata
+
+4.4.0
+-----
+
+* Add force to os-brick disconnect
+* Run cinder driver unit tests
+* RBD: Wrap RBD calls in native threads
+* Update master for stable/2023.1
+* Do not always import boto3
+* rbd: Disable rbd stores if libraries are not available
+* cinder: Disable cinder stores if cinderclient is not installed
+* move attachment\_update to try block
+* Fix misuse of assertTrue
+* Imported Translations from Zanata
+
+4.3.0
+-----
+
+* Replace deprecated UPPER\_CONSTRAINTS\_FILE variable
+* Imported Translations from Zanata
+* Cinder: Add support to extend attached volumes
+* Refactor/restructure glance cinder store
+
+4.2.0
+-----
+
+* Fix tox4 error
+* Add region\_name option to s3 store
+* [test-only] OverflowError running on 32-bit systems
+* Imported Translations from Zanata
+* Switch to 2023.1 Python3 unit tests and generic template name
+* Update master for stable/zed
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+
+4.1.0
+-----
+
+* Tests: Mock sleep in cinder test\_attachment\_create\_retries
+* Swift: Honor \*\_domain\_name parameters
+* Do not loose url queries on redirects
+* Rbd: Deprecate unused rados\_connect\_timeout
+* Add debug logs to cinder store
+* Remove logic for Python <= 2.6
+
+4.0.1
+-----
+
+* Support os-brick specific lock\_path for Cinder
+* Imported Translations from Zanata
+* Remove Python 2 support
+
+4.0.0
+-----
+
+* Update python testing as per zed cycle teting runtime
+* Cinder: Correct exception logging during attach
+* Correct retry interval during attach volume
+* Add coverage for add method
+* Add exception coverage for get, get\_size, delete
+* Add coverage for helper methods
+* Add coverage for get\_cinderclient and \_check\_context
+* Remove redundant try except around volume create
+* Add coverage for StoreLocation
+* Add coverage for get\_cinder\_session
+* Remove six usage
+* Refactor cinder store tests[2/2]
+* Refactor cinder store tests[1/2]
+* Replace FakeObject with MagicMock[2/2]
+* Replace FakeObject with MagicMock[1/2]
+* Update master for stable/yoga
+
+3.0.0
+-----
+
+* Cinder store: Wait for device resize
+* Correct attachment\_complete call
+* Pass valid IP address to os-brick
+* [RBD] Clone v2: Image is unusable if deletion fails
+* Updating python testing classifier as per Yoga testing runtime
+* Imported Translations from Zanata
+* nit: Correct debug log
+* Cleanup devstack jobs
+* Fix documentation build with Sphinx>=4.2.0
+* Fix typos
+* Add Python3 yoga unit tests
+* Update master for stable/xena
+
+2.7.0
+-----
+
+* Xena cycle Release Notes
+* Raise correct exception from "Quota full"
+* Add volume multiattach handling
+* Drop lower-constraints job
+* Glance cinder nfs: Block creating qcow2 volumes
+* Doc: Use Block Storage API v3
+* Add cinder's new attachment support
+
+2.6.0
+-----
+
+* s3: Optimize WRITE\_CHUNKSIZE to minimize an overhead
+* setup.cfg: Replace dashes with underscores
+* Allow any Keystone domain for cinder store
+* vmware: Use cookiejar from oslo.vmware client directly
+* Pass multipath config while creating connector object
+* Add Python3 xena unit tests
+* Update master for stable/wallaby
+* swift: Take into account swift\_store\_endpoint
+
+2.5.0
+-----
+
+* Wallaby cycle Release Notes
+* Run glance functional job on glance\_store
+* Validate volume type during volume create
+* Cinder store: Use v3 API by default
+* Fix lower\_constraints and requirements
+* Replace md5 with oslo version
+
+2.4.0
+-----
+
+* Imported Translations from Zanata
+* Add Python3 wallaby unit tests
+* Update master for stable/victoria
+* Update user/project referencing from context
+
+2.3.0
+-----
+
+* Drop snapshot in use log from ERROR to WARN
+* Add a little more test coverage for rbd resize logic
+* Bring FakeData utility over from glance
+* Correct default type name reference
+* Support Cinder multiple stores
+* Handle sparse images in glance\_store
+* Ramp up rbd resize to avoid excessive calls
+
+2.2.0
+-----
+
+* Copy data files to glance upon installation
+* [Trivial]Add missing white space between words
+* [goal] Migrate glance\_store jobs to focal
+* zuul: glance\_store-src-ceph-tempest replaces a legacy job
+* use stevedore to load extensions
+* requirements: Drop os-testr
+* Remove translation sections from setup.cfg
+* Fix mock import in unit tests
+* Don't allow image creation with encrypted nfs volumes
+
+2.1.0
+-----
+
+* Release notes for Victoria Milestone 1
+* Stop to use the \_\_future\_\_ module
+* Switch to newer openstackdocstheme and reno versions
+* Cap jsonschema 3.2.0 as the minimal version
+* Fix hacking min version to 3.0.1
+* Imported Translations from Zanata
+* Add lock per share for cinder nfs mount/umount
+* Clarify the filesystem\_store\_metadata\_file config option
+* Fix: API returns 503 if one of the store is mis-configured
+* Bump default tox env from py37 to py38
+* Add py38 package metadata
+* Bump cinder/os-brick requirements
+* Use unittest.mock instead of third party mock
+* Imported Translations from Zanata
+* Add Python3 victoria unit tests
+* Enforce constraints for docs dependencies
+* Cleanup py27 support
+* Update hacking for Python3
+* Update master for stable/ussuri
+
+2.0.0
+-----
+
+* Release note for 1.2.0
+* Add config for cinder mounting needs
+* Refactor methods in cinder store
+* Add S3 store support to glance\_store
+* Fix for BufferedReader sets is\_zero\_size true for a chunk
+* Image upload fails if cinder multipath is enabled
+* Drop support for tempest-full
+* Restore quotes removal for swift config in Python3
+* Drop python 2.7 support and testing
+* Re-use swift\_store\_cacert for Keystone session
+* doc: Clean up unnecessary left vertical lines
+* Imported Translations from Zanata
+
+1.1.0
+-----
+
+* Remove sheepdog store driver
+* Add release notes link in readme
+* Imported Translations from Zanata
+* Release note for 1.0.1
+* Update master for stable/train
+* Register reserved store configs
+* Remove warning filter
+* Set zero size only when nothing is written
+* Fix option load for swift/vmware
+
+1.0.0
+-----
+
+* Release note and documentation for 1.0.0
+* Deprecate Sheepdog driver
+* Change location metadata key 'backend' to 'store'
+* Remove sheepdog tests from zuul config
+* Add Python 3 Train unit tests
+
+0.29.1
+------
+
+* Add 0.29.1 releasenotes
+* Revert "Change location metadata key 'backend' to 'store'"
+
+0.29.0
+------
+
+* Rethinking file system access
+* Remove outdated line in tox.ini
+* Change location metadata key 'backend' to 'store'
+* Add location prefix url to store instance
+* Add releasenote for option removal
+* Removed 'store\_capabilities\_update\_min\_interval' config option
+* Dropping the py35 testing
+* Modify deprecation warning for stores options
+* Cap sphinx for py2 to match global requirements
+* Replace git.openstack.org URLs with opendev.org URLs
+* Fix failing tips-py35 jobs
+* OpenDev Migration Patch
+* Do not include ETag when puting manifest in chunked uploads
+* Update irrelevant-files for tempest tests
+* Python3: Fix return type on CooperativeReader.read
+* Uncap jsonschema
+* Update master for stable/stein
+* Prevent unicode object error from zero-byte read
+* Return bytes even when get()ing a zero-byte image from swift
+
+0.28.0
+------
+
+* Stein cycle Release Notes
+* Update help text for rbd\_ceph\_conf
+* Filesystem driver: add chunk size config option
+* Fix python3 compatibility of rbd get\_fsid
+* Do not raise StopIteration
+* add python 3.7 unit test job
+* Fix some types in the FS and VMware drivers
+* Imported Translations from Zanata
+* Update mailinglist from dev to discuss
+* Use template for lower-constraints
+* Update deprecation notices
+* Catch rbd NoSpace exception
+* Remove moxstubout usage
+
+0.27.0
+------
+
+* Add statement explaining "tips" job configuration
+* Provision to add new config options in sample config file
+* Imported Translations from Zanata
+* add lib-forward-testing-python3 test job
+* add python 3.6 unit test job
+* switch documentation job to new PTI
+* Fix defaults for ConfigParser
+* Change rbd default conf path
+* import zuul job settings from project-config
+* remove bandit from testing
+* Refactor periodic "tips" jobs
+* Imported Translations from Zanata
+* Move doc8 to test requirements
+* Remove team diversity tags note in README
+* Wrap interface function for multihash correctly
+* cinder: Support os-brick privsep filters
+* Update reno for stable/rocky
+
+0.26.0
+------
+
+* Consider Cinder back-end as production ready
+* Remove config option help translation
+* Deprecate store\_add\_to\_backend()
+* Multihash Implementation for Glance
+
+0.25.0
+------
+
+* Address multi store nits
+* Add release notes for 0.25.0
+* Multi store support for cinder driver
+* Update tox.ini to conform to the PTI
+* Follow the new PTI for document build
+* Multi store support for http, swift, sheepdog and vmware driver
+* Enable multi store support for glance
+* Deprecate stores, default\_store config options
+* specify region on creating cinderclient
+* cinder: Specify mountpoint host param to attach API
+* Deprecate store\_capabilities\_update\_min\_interval
+* Update links in README
+
+0.24.0
+------
+
+* use only exceptions for uri validations
+* fix tox python3 overrides
+* Update conf.py to align with openstackdocstheme
+* Add periodic tips jobs
+* Add glance\_store disclaimer to docs
+* Remove tox\_install.sh
+* uncap eventlet
+* add lower-constraints job
+* Fix wrong links in glance\_store
+* Updated from global requirements
+* Updated from global requirements
+* Clean imports in code
+* Imported Translations from Zanata
+* Migrate legacy jobs to project repository
+* Updated from global requirements
+* Imported Translations from Zanata
+* Add doc8 to pep8 check for glance\_store project
+* Add .stestr to gitignore
+* Update reno for stable/queens
+* Updated from global requirements
+* process spelling error
+* Imported Translations from Zanata
+
+0.23.0
+------
+
+* Add Queens release note
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Fix some wrong url and add license
+* Updated from global requirements
+* Updated from global requirements
+* Fix BufferedReader writing zero size chunks
+* Updated from global requirements
+* Updated from global requirements
+* Use cached auth\_ref instead of gettin a new one each time
+* Remove setting of version/release from releasenotes
+* Updated from global requirements
+* Updated from global requirements
+* Imported Translations from Zanata
+* TrivialFix: Correct reST field lists in docstrings
+* Revert "Remove team:diverse-affiliation from tags"
+* Expand sz to size
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* Update reno for stable/pike
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Remove team:diverse-affiliation from tags
+
+0.21.0
+------
+
+* Updated from global requirements
+* Add release note for Pike
+* Cinder driver: TypeError in \_open\_cinder\_volume
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* set warning-is-error for documentation build
+* switch from oslosphinx to openstackdocstheme
+* rearrange existing documentation according to the new standard layout
+* Updated from global requirements
+* Updated from global requirements
+* Fix html\_last\_updated\_fmt for Python3
+* Fixed tests due to updated oslo.config
+* Initialize privsep root\_helper command
+* Don't fail when trying to unprotect unprotected snapshot on RBD
+* Updated from global requirements
+* Add python 3.5 in classifier and envlist
+* Imported Translations from Zanata
+* Update maintainer's email address
+* Updated from global requirements
+* Buffered reader: Upload recovery for swift store
+* Updated from global requirements
+* Replace six.iteritems() with .items()
+* Removes unnecessary utf-8 coding for glance\_store
+* Use HostAddressOpt for store opts that accept IP and hostnames
+* Updated from global requirements
+* An unit test passes because is launched as non-root user
+* Update test requirement
+* Updated from global requirements
+* Updated from global requirements
+* Fix SafeConfigParser DeprecationWarning in Python 3.2+
+* Update reno for stable/ocata
+* Correct error msg variable that could be unassigned
+* Fixing string formatting bug in log message
+
+0.20.0
+------
+
+* Updated from global requirements
+* Remove debtcollector in requirements.txt
+* Log at error when we intend to reraise the exception
+* Suppress oslo-config DeprecationWarning during functional test
+* Disable verification for Keystone session in Swift
+
+0.19.0
+------
+
+* Raise exc when using multi-tenant and swift+config
+* Updated from global requirements
+* Use storage\_url in DB for multi-tenant swift store
+* Add alt text for badges
+* Fix a typo in help text
+* Show team and repo badges on README
+* take into consideration created volume size in cinder backend
+* Updated from global requirements
+* Move rootwrap config files from etc/\* into etc/glance/\*
+* Update README
+* Convert to keystoneauth
+* Updated from global requirements
+* Fix a typo in rootwrap.conf and glance\_cinder\_store.filters
+* Fix dbg msg when swift can't determine image size
+* Refactor get\_manager\_for\_store in an OO manner
+* Add cinder\_volume\_type to cinder store configuration
+* Enable release notes translation
+* Updated from global requirements
+* Do not require entry-point dependencies in tests
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Sheepdog: fix command execution failure
+* Update home-page url in setup.cfg
+* Do not call image.stat() when we only need the size
+* TrivialFix: Merge imports in code
+* standardize release note page ordering
+* Clean imports in code
+* Reason to return sorted list of drivers for opts
+* Updated from global requirements
+* Always return a sorted list of drivers for configs
+* Fix doc build if git is absent
+* Improve tools/tox\_install.sh
+* Update reno for stable/newton
+
+0.18.0
+------
+
+* Fix header passed to requests
+* Updated from global requirements
+
+0.17.0
+------
+
+* Add release notes for 0.17.0
+* Release note for glance\_store configuration opts
+* Improving help text for Swift store opts
+* Improving help text for Swift store util opts
+* Improve help text of cinder driver opts
+* Fix help text of swift\_store\_config\_file
+* Improving help text for backend store opts
+* Remove "Services which consume this" section
+* Improve the help text for Swift driver opts
+* Updated from global requirements
+* Improving help text for Sheepdog opts
+* Use constraints for all tox environments
+* Improve help text of http driver opts
+* Improve help text of filesystem store opts
+* Improve help text of rbd driver opts
+* Improving help text for Glance store Swift  opts
+* Remove deprecated exceptions
+* Improve the help text for vmware datastore driver opts
+* Updated from global requirements
+
+0.16.0
+------
+
+* Updated from global requirements
+* Updated from global requirements
+* Remove S3 driver
+
+0.15.0
+------
+
+* Fix cinder config string as per current i18n state
+* Sheepdog:modify default addr
+* Cleanup i18n marker functions to match Oslo usage
+* Updated from global requirements
+* Don't include openstack/common in flake8 exclude list
+
+0.14.0
+------
+
+* Add bandit to pep8 and bandit testenv
+* Remove unused variable in vmware store
+* Imported Translations from Zanata
+* Split functional tests apart
+* Updated from global requirements
+* Check that size is a number
+* Replace dict.iterkeys with six.iterkeys to make PY3 compatible
+* cinder: Fix get\_size return value
+* The function add calculation size\_gb need improve
+* Updated from global requirements
+* Updated from global requirements
+* Fix argument order for assertEqual to (expected, observed)
+* Updated from global requirements
+* Updated from global requirements
+* Remove -c from tox.ini
+* tox respects upper-constraints.txt
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Fix minor misspellings affecting Config Reference Guide
+* Remove verbose option from glance\_store tests
+* Updated from global requirements
+* Updated from global requirements
+* Improve help text of swift driver opts
+* Updated from global requirements
+* Add functional tests for swift
+* Imported Translations from Zanata
+* Updated from global requirements
+* Updated from global requirements
+* Fix releasenotes to pass reno gates
+* Updated from global requirements
+* tox: use os-testr instead of testr
+* Fix swiftclient mocks
+* Deprecate swift driver options properly
+* Fix typos in config files
+* Setup defaults for swift driver authentication
+* Fix doc generation warnings and errors
+* trivial:fixing one W503 pep8 error
+* Module docs are not generated
+* Fix cinder store to support Cinder RemoteFS backends
+* Missing params in store\_add\_to\_backend docstring
+* Mock swiftclient's functions in tests
+* Update reno for stable/mitaka
+
+0.13.0
+------
+
+* Add https ca\_file and insecure options to VMware Store
+* swift: Do not search storage\_url for ks v2
+
+0.12.0
+------
+
+* Fix misspelling in the releasenote support-cinder-upload
+* Add new config options for HTTPS store
+* Implement get, add and delete for cinder store
+* Implement re-authentication for swift driver
+* Implement swift store connection manager
+* Updated from global requirements
+* test\_http\_get\_redirect is not testing redirects correctly
+* Switch VMWare Datastore to use Requests
+* Updated from global requirements
+* Add base for functional tests
+* Add small image verifier for swift backend
+* Switch HTTP store to using requests
+
+0.11.0
+------
+
+* Change approach to request storage url for multi-tenant store
+* Remove unused parameters from swift connection init
+* Sheepdog: fix image-download failure
+* LOG.warn is deprecated in python3
+* Updated from global requirements
+* Updated from global requirements
+* Use url\_for from keystoneclient in swift store
+* Remove deprecated  datastore\_name, datacenter\_path
+* Add backend tests from glance
+* Fix some inconsistency in docstrings
+* Updated from global requirements
+* Change Swift zero-size chunk behaviour
+* Sheepdog: fix upload failure in API v2
+* Remove unnecessary re-raise of NotFound exception
+* Updated from global requirements
+* Add signature verifier to backend drivers
+* Use oslo\_utils.encodeutils.exception\_to\_unicode()
+* Fix default mutables for set\_acls
+* Deprecate unused Exceptions
+* Remove unnecessary auth module
+* Updated from global requirements
+* Deprecate the S3 driver
+* Document supported drivers and maintainers
+* Remove the gridfs driver
+* Set documented default directory for filesystem
+* Imported Translations from Zanata
+* Updated from global requirements
+* Swift store: do not send a 0 byte chunk
+* Store.get\_size: handle HTTPException
+* Replace deprecated library function os.popen() with subprocess
+* Updated from global requirements
+* Deprecated tox -downloadcache option removed
+* Add docs section to tox.ini
+* Replace assertEqual(None, \*) with assertIsNone in tests
+* Updated from global requirements
+* Remove duplicate keys from dictionary
+* Remove unreachable code
+* Sheepdog: Change storelocation format
+* Updated from global requirements
+* Add reno for release notes management in glance\_store
+* Put py34 first in the env order of tox
+* Updated from global requirements
+* Add list of supported stores to help
+* Add functional testing devstack gate hooks
+
+0.10.0
+------
+
+* Rel notes for 0.10.0
+* Updated from global requirements
+* Remove useless config.py file
+* vmware: check for response body in error conditions
+* remove default=None for config options
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* Updated from global requirements
+* Remove deprecated glance\_store opts from default section
+* Updated from global requirements
+* Improving GlanceStoreException
+* Activate pep8 check that \_ is imported
+* '\_' is used by i18n
+* VMware: Fix missing space in error message
+* Handle swift store's optional dependency
+* Fix swift store tests for latest swiftclient
+
+0.9.1
+-----
+
+* rbd: re-add the absolute\_import and with\_statement imports
+
+0.9.0
+-----
+
+*  Release notes 0.9.0 and corrected library version
+* Updated from global requirements
+* Catch InvalidURL when requesting store size
+* Imported Translations from Transifex
+* Add proxy support to S3 Store
+* Prevent glance-api hangups during connection to rbd
+* rbd driver cannot delete residual image from ceph in some cases
+
+0.8.0
+-----
+
+* Imported Translations from Transifex
+* Add explicit dependencies for store dependencies
+* Support V3 authentication with swift
+
+0.7.1
+-----
+
+* rbd: make sure features is an int when passed to librbd.create
+
+0.7.0
+-----
+
+* setup.cfg: add Python 3 classifiers
+* Remove usage of assert\_called\_once in mocks
+* Add .eggs/\* to .gitignore
+* Imported Translations from Transifex
+* Updated from global requirements
+* Make cinderclient a more optional dependency
+* Port S3 driver to Python 3
+* Do not used named args when using swiftclient
+* logging failed exception info for add image operation
+* Fix random test error in swift store delete
+* Port swift driver to Python 3
+* Port vmware driver to Python 3
+* RBD: Reading rbd\_default\_features from ceph.conf
+* Move glance\_store tests into the main package
+* Use six.moves to fix imports on Python 3
+* Move python-cinderclient to test-requirements.txt
+* Updated from global requirements
+
+0.6.0
+-----
+
+* Add release notes for 0.6.0
+* Drop py26 support
+* Port remaining tests to Python 3
+* Fix Python 3 issues
+* Close a file to fix a resource warning on Python 3
+* Port exception\_to\_str() to Python 3
+* Disable propagating BadStoreConfiguration
+* Sync up with global-requirements
+
+0.5.0
+-----
+
+* Add release notes for 0.5.0
+* Drop use of 'oslo' namespace package
+* Fix RBD delete image on creation failure
+* Use is\_valid\_ipv6() from oslo.utils
+* Properly instantiate Forbidden exception
+* Update README to work with release tools
+* Remove ordereddict from requirements
+* gridfs: add pymongo to test-requirements and update tests
+* Add release notes for 0.1.10-0.3.0
+* Only warn on duplicate path on fs backend
+* Propagate BadStoreConfiguration to library user
+* Handle optional dependency in vmware store
+* Update oslo libraries
+* Initialize vmware session during store creation
+
+0.4.0
+-----
+
+* Add release notes for 0.4.0
+* Fix intermittent failure in test\_vmware\_store
+* Deprecate the gridfs store
+* Remove incubative openstack.common.context module
+* Update help text with sample conf
+* Use oslo\_config.cfg.ConfigOpts in glance\_store
+* Make dependency on boto entirely conditional
+* Move from oslo.utils to oslo\_utils (supplement)
+* Fix timeout during upload from slow resource
+
+0.3.0
+-----
+
+* Throw NotFound exception when template is gone
+* Deprecate VMware store single datastore options
+* Use oslo\_utils.units where appropriate
+* VMware: Support Multiple Datastores
+
+0.2.0
+-----
+
+* Correct such logic in store.get() when chunk\_size param provided
+* Support for deleting images stored as SLO in Swift
+* Enable DRIVER\_REUSABLE for vmware store
+
+0.1.12
+------
+
+* Show fully qualified store name in update\_capabilities() logging
+* Move to hacking 0.10
+* Fix sorting query string keys for arbitrary url schemes
+* Unify using six.moves.range rename everywhere
+
+0.1.11
+------
+
+* Remove duplicate key
+* Add coverage report to run\_test.sh
+* Use a named enum for capability values
+* Check VMware session before uploading image
+* Add capabilities to storage driver
+* Fixing PEP8 E712 and E265
+* Convert httpretty tests to requests-mock
+* Replace snet config with endpoint config
+* Rename oslo.concurrency to oslo\_concurrency
+* Remove retry on failed uploads to VMware datastore
+* Remove old dependencies
+* Validate metadata JSON file
+* Use default datacenter\_path from oslo.vmware
+* Remove unused exception StorageQuotaFull
+* Move from oslo.config to oslo\_config
+* Move from oslo.utils to oslo\_utils
+* Add needed extra space to error message
+* Define a new parameter to pass CA cert file
+* Use testr directly from tox
+* Raise appropriate exception if socket error occurs
+* Swift Store to use Multiple Containers
+* Use testr directly from tox
+* Remove deprecated options
+* Correct GlanceStoreException to provide valid message - glance\_store
+* Catch NotFound exception in http.Store get\_size
+* VMware store: Re-use api session token
+
+0.1.10
+------
+
+
+0.1.9
+-----
+
+* Test swift multi-tenant store get context
+* Test swift multi-tenant store add context
+* Use oslo.concurrency
+* Move cinder store to use auth\_token
+* Swift Multi-tenant store: Fix image upload
+* Use statvfs instead of df to get available space
+* Fix public image ACL in multi-tenant Swift mode
+* Updated run\_tests.sh to run tests in debug mode
+* Remove validate\_location
+* Imported Translations from Transifex
+* Add coverage to test-requirements.txt
+* Imported Translations from Transifex
+* Switch to using oslo.utils
+* Remove network\_utils
+* Recover from errors while deleting image segments
+* VMware store: Use the Content-Length if available
+* Backporting S3 multi-part upload functionality to glace\_store
+* Make rbd store's pool handling more universal
+* s3\_store\_host parameter with port number
+* Enhance configuration handling
+* Enable F841 check
+* Portback part change of adding status field to image location
+* Mark glance\_store as being a universal wheel
+* Imported Translations from Transifex
+* Use oslo.serialization
+* Fix H402
+* Portback part change of enabling F821 check
+* Adding common.utils.exception\_to\_str() to avoid encoding issue
+* Replace stubout with oslotest.moxstubout
+* Fix RBD store to use READ\_CHUNKSIZE and correct return of get()
+* Add a run\_tests.sh
+* Run tests parallel by default
+* Add ordereddict to reqs for py2.6 compatibility
+* rbd: fix chunk size units
+* Imported Translations from Transifex
+* Stop using intersphinx
+* Cleanup shebang in non-executable module
+* Correct Sheepdog store configuration
+* Correct base class of no\_conf driver
+* Handle session timeout in the VMware store
+* Add entry-point for oslo.config options and update registering logic
+* Configure the stores explicitly
+* Imported Translations from Transifex
+* Return the right filesize when chunk\_size != None
+* Allowing operator to configure a permission for image file in fs store
+* Align swift's store API
+
+0.1.7
+-----
+
+* Add \`OPTIONS\` attribute to swift.Store function
+
+0.1.5
+-----
+
+* Add missing stores to setup.cfg
+* Set group for DeprecatedOpts
+* Complete random\_access for the filesystem store
+* Work toward Python 3.4 support and testing
+
+0.1.3
+-----
+
+* Register store's configs w/o creating instances
+
+0.1.2
+-----
+
+* Add deprecated options support for storage drivers
+* Rename locale files for glance\_store rename
+* Update .gitreview for project rename
+
+0.1.1
+-----
+
+* Rename glance.store to glance\_store
+* Port of 97882f796c0e8969c606ae723d14b6b443e2e2f9
+* Port of 502be24afa122eef08186001e54c1e1180114ccf
+* Fix collection order issues and unit test failures
+
+0.1.0
+-----
+
+
+0.0.1a2
+-------
+
+* Fix development classifier
+* Imported Translations from Transifex
+* Package glance's package entirely
+
+0.0.1a1
+-------
+
+* Split CHUNKSIZE into WRITE/READ\_CHUNKSIZE
+* Port swift store
+* Add validate\_location
+* Fix some Exceptions incompatibilities
+* Imported Translations from Transifex
+* Setup for glance.store for translation
+* Set the right classifiers in setup.cfg
+* Remove version string from setup.cfg
+* Add .gitreview to the repo
+* Fix flake8 errors
+* Adopt oslo.i18n
+* Pull multipath support from glance/master
+* Update from oslo-incubator
+* Pass offset and chunk\_size to the \`get\` method
+* Migrate vmware store
+* Move FakeHTTPResponse to a common utils module
+* Removed commented code
+* Remove deprecated \_schedule\_delayed\_delete\_from\_backend function
+* BugFix: Point to the exceptions module
+* BugFix: define scheme outside the \`try\` block
+* Add a way to register store options
+* Update functions signatures w/ optional context
+* Remove old scrubber options
+* Move exceptions out of common and add backends.py
+* Use exception
+* Remove dependency on oslo-log
+* Add offset and chunk\_size to the get method
+* Migrate the rbd store
+* Use register\_store\_schemes everywhere
+* Add missing context keyword to the s3 store
+* Migrate cinder store
+* Remove location\_strategy, it belongs to Glance
+* S3 store ported
+* Move options registration to \_\_init\_\_
+* GridFS Store
+* Port sheepdog and its test suite
+* Update from oslo-inc and added processutils
+* Fix http store tests
+* Added fake driver, restored base tests, fixed load driver issue
+* Use context when needed
+* Add context=None to http store methods
+* Remove old exceptions
+* HTTP migrated
+* Accept a message keyword in exceptions
+* Filesystem driver restored
+* Move drivers under \_driver
+* Added testr
+* Config & Import fixes
+* Move base test to glance/store
+* Deprecate old options, make the list shorter
+* Add glance.store common
+* Add tests w/ some fixes, although they don't run yet
+* Update gitignore
+* Add requirements and testr
+* Add oslo-inc modules
+* Copying from glance
diff -pruN 4.9.1-2/PKG-INFO 5.0.0-0ubuntu2/PKG-INFO
--- 4.9.1-2/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/PKG-INFO	2025-07-10 09:13:41.907623800 +0000
@@ -0,0 +1,103 @@
+Metadata-Version: 2.1
+Name: glance_store
+Version: 5.0.0
+Summary: OpenStack Image Service Store Library
+Home-page: https://docs.openstack.org/glance_store/latest/
+Author: OpenStack
+Author-email: openstack-discuss@lists.openstack.org
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Requires-Python: >=3.10
+License-File: LICENSE
+Requires-Dist: oslo.config>=5.2.0
+Requires-Dist: oslo.i18n>=3.15.3
+Requires-Dist: oslo.serialization!=2.19.1,>=2.18.0
+Requires-Dist: oslo.utils>=4.7.0
+Requires-Dist: oslo.concurrency>=3.26.0
+Requires-Dist: stevedore>=1.20.0
+Requires-Dist: eventlet!=0.18.3,!=0.20.1,>=0.18.2
+Requires-Dist: jsonschema>=3.2.0
+Requires-Dist: keystoneauth1>=3.4.0
+Requires-Dist: python-keystoneclient>=3.8.0
+Requires-Dist: requests>=2.14.2
+Provides-Extra: vmware
+Requires-Dist: oslo.vmware>=3.6.0; extra == "vmware"
+Provides-Extra: swift
+Requires-Dist: python-swiftclient>=3.2.0; extra == "swift"
+Provides-Extra: cinder
+Requires-Dist: python-cinderclient>=4.1.0; extra == "cinder"
+Requires-Dist: os-brick>=6.3.0; extra == "cinder"
+Requires-Dist: oslo.rootwrap>=5.8.0; extra == "cinder"
+Requires-Dist: oslo.privsep>=1.23.0; extra == "cinder"
+Provides-Extra: s3
+Requires-Dist: boto3>=1.9.199; extra == "s3"
+Provides-Extra: test
+Requires-Dist: hacking<6.2.0,>=6.1.0; extra == "test"
+Requires-Dist: doc8>=0.6.0; extra == "test"
+Requires-Dist: coverage!=4.4,>=4.0; extra == "test"
+Requires-Dist: ddt>=1.4.4; extra == "test"
+Requires-Dist: fixtures>=3.0.0; extra == "test"
+Requires-Dist: requests-mock>=1.2.0; extra == "test"
+Requires-Dist: retrying>=1.3.3; extra == "test"
+Requires-Dist: stestr>=2.0.0; extra == "test"
+Requires-Dist: testscenarios>=0.4; extra == "test"
+Requires-Dist: testtools>=2.2.0; extra == "test"
+Requires-Dist: oslotest>=3.2.0; extra == "test"
+Requires-Dist: openstacksdk>=0.10.0; extra == "test"
+Requires-Dist: boto3>=1.9.199; extra == "test"
+Requires-Dist: oslo.vmware>=3.6.0; extra == "test"
+Requires-Dist: httplib2>=0.9.1; extra == "test"
+Requires-Dist: python-swiftclient>=3.2.0; extra == "test"
+Requires-Dist: python-cinderclient>=4.1.0; extra == "test"
+Requires-Dist: os-brick>=2.6.0; extra == "test"
+Requires-Dist: oslo.rootwrap>=5.8.0; extra == "test"
+Requires-Dist: oslo.privsep>=1.23.0; extra == "test"
+
+========================
+Team and repository tags
+========================
+
+.. image:: https://governance.openstack.org/tc/badges/glance_store.svg
+    :target: https://governance.openstack.org/tc/reference/tags/index.html
+    :alt: The following tags have been asserted for the Glance Store
+          Library:
+          "project:official",
+          "stable:follows-policy",
+          "vulnerability:managed".
+          Follow the link for an explanation of these tags.
+.. NOTE(rosmaita): the alt text above will have to be updated when
+   additional tags are asserted for glance_store.  (The SVG in the
+   governance repo is updated automatically.)
+
+.. Change things from this point on
+
+Glance Store Library
+====================
+
+Glance's stores library
+
+This library has been extracted from the Glance source code for the
+specific use of the Glance and Glare projects.
+
+The API it exposes is not stable, has some shortcomings, and is not a
+general purpose interface. We would eventually like to change this,
+but for now using this library outside of Glance or Glare will not be
+supported by the core team.
+
+* License: Apache License, Version 2.0
+* Documentation: https://docs.openstack.org/glance_store/latest/
+* Source: https://opendev.org/openstack/glance_store/
+* Bugs: https://bugs.launchpad.net/glance-store
+* Release notes: https://docs.openstack.org/releasenotes/glance_store/index.html
+
diff -pruN 4.9.1-2/debian/changelog 5.0.0-0ubuntu2/debian/changelog
--- 4.9.1-2/debian/changelog	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/changelog	2025-08-19 10:21:03.000000000 +0000
@@ -1,214 +1,240 @@
-python-glance-store (4.9.1-2) unstable; urgency=medium
+python-glance-store (5.0.0-0ubuntu2) questing; urgency=medium
 
-  * Uploading to unstable.
+  * d/glance_sudoers: Drop override causing compatibility issues with
+    sudo-rs. (LP: #2120708)
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 28 Mar 2025 08:30:42 +0100
+ -- Guillaume Boutry <guillaume.boutry@canonical.com>  Tue, 19 Aug 2025 12:21:03 +0200
 
-python-glance-store (4.9.1-1) experimental; urgency=medium
+python-glance-store (5.0.0-0ubuntu1) questing; urgency=medium
 
-  * New upstream release.
-  * d/watch: switch to version=4 and mode=git.
+  [ Guillaume Boutry ]
+  * d/gbp.conf, .launchpad.yaml: Sync from cloud-archive-tools for
+    flamingo.
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 26 Feb 2025 11:19:30 +0100
+  [ Myles Penner ]
+  * New upstream release for OpenStack Flamingo. (LP: #2116155)
+  * d/control: Align (Build-)Depends with upstream.
+  * d/watch: Add Flamingo key verification.
+  * d/u/signing-key.asc: Add Flamingo public key.
 
-python-glance-store (4.8.1-3) unstable; urgency=medium
+ -- Myles Penner <myles.penner@canonical.com>  Tue, 15 Jul 2025 09:39:49 -0700
 
-  * Switch to pybuild (Closes: #1090506).
+python-glance-store (4.9.1-0ubuntu1) plucky; urgency=medium
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 19 Dec 2024 10:44:21 +0100
+  * New upstream release for OpenStack Epoxy.
 
-python-glance-store (4.8.1-2) unstable; urgency=medium
+ -- James Page <james.page@ubuntu.com>  Fri, 28 Feb 2025 14:18:24 +0000
 
-  * Uploading to unstable.
+python-glance-store (4.9.0-0ubuntu1) plucky; urgency=medium
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 19 Sep 2024 17:03:00 +0200
+  * d/gbp.conf, .launchpad.yaml: Sync from cloud-archive-tools for
+    epoxy.
+  * New upstream release for OpenStack Epoxy.
 
-python-glance-store (4.8.1-1) experimental; urgency=medium
+ -- James Page <james.page@ubuntu.com>  Wed, 15 Jan 2025 14:41:42 +0000
 
-  * New upstream release.
-
- -- Thomas Goirand <zigo@debian.org>  Mon, 26 Aug 2024 10:34:40 +0200
+python-glance-store (4.8.1-0ubuntu1) oracular; urgency=medium
 
-python-glance-store (4.7.0-4) unstable; urgency=medium
+  * d/gbp.conf: upstream-branch -> upstream-dalmatian.
+  * New upstream release for OpenStack Dalmatian.
 
-  * Remove build-depends on python3-boto (Closes: #1069646).
+ -- James Page <james.page@ubuntu.com>  Wed, 25 Sep 2024 10:20:18 +0100
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 22 Apr 2024 14:12:33 +0200
+python-glance-store (4.8.0-0ubuntu1) oracular; urgency=medium
 
-python-glance-store (4.7.0-3) unstable; urgency=medium
+  * New upstream release. 
 
-  * Remove extraneous dependency on python3-six (Closes: #1068970).
+ -- James Page <james.page@ubuntu.com>  Wed, 07 Aug 2024 08:16:02 +0100
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 18 Apr 2024 13:50:10 +0200
+python-glance-store (4.7.0-0ubuntu1) noble; urgency=medium
 
-python-glance-store (4.7.0-2) unstable; urgency=medium
+  * New upstream point release for OpenStack Caracal.
 
-  * Uploading to unstable.
+ -- James Page <james.page@canonical.com>  Fri, 08 Mar 2024 13:51:27 +0000
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 04 Apr 2024 09:09:35 +0200
+python-glance-store (4.6.1-0ubuntu2) noble; urgency=medium
 
-python-glance-store (4.7.0-1) experimental; urgency=medium
+  [ Corey Bryant ]
+  * d/gbp.conf, .launchpad.yaml: Sync from cloud-archive-tools for
+    caracal.
 
-  * New upstream release.
+  [ James Page ]
+  * d/control: Drop BD on python3-boto (LP: #2052437).
+  * d/rules: remove duplicated configuration files from /usr/etc.
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 29 Feb 2024 10:16:29 +0100
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 07 Feb 2024 10:06:37 +0000
 
-python-glance-store (4.6.1-3) unstable; urgency=medium
+python-glance-store (4.6.1-0ubuntu1) mantic; urgency=medium
 
-  * autopkgtest: blacklist TestConnectorBase.test_factory_3 that is failing on
-    ppc64el and s390x.
+  * New upstream release for OpenStack Bobcat.
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 07 Nov 2023 16:20:36 +0100
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 05 Sep 2023 15:23:41 -0400
 
-python-glance-store (4.6.1-2) unstable; urgency=medium
+python-glance-store (4.6.0-0ubuntu1) mantic; urgency=medium
 
-  * Uploading to unstable.
+  * New upstream release for OpenStack Bobcat.
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 04 Oct 2023 21:38:57 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 11 Jul 2023 13:52:38 -0400
 
-python-glance-store (4.6.1-1) experimental; urgency=medium
+python-glance-store (4.5.0-0ubuntu1) mantic; urgency=medium
 
-  * New upstream release.
+  * d/gbp.conf, .launchpad.yaml: Sync from cloud-archive-tools for
+    bobcat.
+  * .launchpad.yaml: Add netloc to no_proxy to fix failing test.
+  * New upstream release for OpenStack Bobcat.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/CVE-2023-2088.patch: Dropped. Fixed in upstream release.
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 31 Aug 2023 10:47:22 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 08 Jun 2023 16:54:08 -0400
 
-python-glance-store (4.6.0-1) experimental; urgency=medium
+python-glance-store (4.3.0-0ubuntu4) mantic; urgency=medium
 
-  * New upstream release.
+  * SECURITY UPDATE: Unauthorized File Access (LP: #2021980)
+    - debian/patches/CVE-2023-2088.patch: Add force to os-brick
+      disconnect.
+    - CVE-2023-2088
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 29 Aug 2023 16:15:05 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 31 May 2023 14:53:17 -0400
 
-python-glance-store (4.3.1-4) unstable; urgency=medium
+python-glance-store (4.3.0-0ubuntu3) mantic; urgency=medium
 
-  * Cleans better (Closes: #1048440).
+  * SECURITY REGRESSION: Regressions in other projects (LP: #2020111)
+    - debian/patches/series: Do not apply CVE-2023-2088.patch until
+      patches are ready for all upstream OpenStack projects.
+    - CVE-2023-2088
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 22 Aug 2023 10:50:46 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 18 May 2023 11:09:59 -0400
 
-python-glance-store (4.3.1-3) unstable; urgency=medium
+python-glance-store (4.3.0-0ubuntu2) mantic; urgency=medium
 
-  * New upstream release:
-    - include CVE-2023-2088 patch.
-  * Uploading to unstable.
+  * SECURITY UPDATE: Unauthorized File Access
+    - debian/patches/CVE-2023-2088.patch: Add force to os-brick
+      disconnect.
+    - CVE-2023-2088
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 19 Jun 2023 10:36:54 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 05 May 2023 13:12:36 +0200
 
-python-glance-store (4.3.0-2) experimental; urgency=medium
+python-glance-store (4.3.0-0ubuntu1) lunar; urgency=medium
 
-  * CVE-2023-2088: Unauthorized volume access through deleted volume
-    attachments. Applied upstream patch: Add force to os-brick disconnect.
-    (Closes: #1035978).
+  * New upstream release for OpenStack Antelope.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 12 May 2023 08:46:22 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 22 Feb 2023 13:13:26 -0500
 
-python-glance-store (4.3.0-1) experimental; urgency=medium
+python-glance-store (4.2.0-0ubuntu1) lunar; urgency=medium
 
-  * New upstream release.
-  * Removed dependency versions satisfied in Bookworm.
-  * Removed OverflowError_running_on_32-bit_systems.patch applied upstream.
+  * New upstream release for OpenStack Antelope.
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 21 Feb 2023 14:58:25 +0100
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 12 Jan 2023 15:23:57 -0500
 
-python-glance-store (4.1.0-3) unstable; urgency=medium
+python-glance-store (4.1.0-0ubuntu1) kinetic; urgency=medium
 
-  * Add OverflowError_running_on_32-bit_systems.patch.
+  * New upstream release for OpenStack Zed.
 
- -- Thomas Goirand <zigo@debian.org>  Sat, 01 Oct 2022 19:58:18 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 08 Sep 2022 17:51:07 -0400
 
-python-glance-store (4.1.0-2) unstable; urgency=medium
+python-glance-store (4.0.1-0ubuntu2) kinetic; urgency=medium
 
-  * Uploading to unstable.
+  * d/control: Update standards version to 4.6.1.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 23 Sep 2022 09:07:49 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 13 Jul 2022 15:57:08 -0400
 
-python-glance-store (4.1.0-1) experimental; urgency=medium
+python-glance-store (4.0.1-0ubuntu1) kinetic; urgency=medium
 
-  * New upstream release.
-  * Add autopkgtest.
+  * New upstream release for OpenStack Zed.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 29 Aug 2022 17:28:59 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 13 Jul 2022 15:27:31 -0400
 
-python-glance-store (3.0.0-2) unstable; urgency=medium
+python-glance-store (4.0.0-0ubuntu1) kinetic; urgency=medium
 
-  * Uploading to unstable.
+  * New upstream release for OpenStack Zed.
+  * d/control, d/rules: Switch to debhelper compat 13 and switch to pybuild.
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 24 Mar 2022 12:10:35 +0100
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 31 May 2022 13:59:45 -0400
 
-python-glance-store (3.0.0-1) experimental; urgency=medium
+python-glance-store (3.0.0-0ubuntu1) jammy; urgency=medium
 
-  * New upstream releasse.
+  * New upstream release for OpenStack Yoga.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 18 Feb 2022 16:58:57 +0100
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 01 Mar 2022 14:03:38 -0500
 
-python-glance-store (2.7.0-2) unstable; urgency=medium
+python-glance-store (2.7.0-0ubuntu1) impish; urgency=medium
 
-  * Uploading to unstable.
+  * New upstream release for OpenStack Xena.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 29 Sep 2021 10:27:29 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 07 Sep 2021 14:51:14 -0400
 
-python-glance-store (2.7.0-1) experimental; urgency=medium
+python-glance-store (2.6.0-0ubuntu1) impish; urgency=medium
 
-  [ Mickael Asseline ]
-  * New upstream release.
-  * Added myself in copyright and uploaders.
-  * Added python3-retrying to build-depends.
+  * New upstream release for OpenStack Xena.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 24 Aug 2021 10:15:46 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 19 Jul 2021 13:55:21 -0400
 
-python-glance-store (2.5.0-2) unstable; urgency=medium
+python-glance-store (2.5.0-0ubuntu1) hirsute; urgency=medium
 
-  * Upload to unstable.
+  * New upstream release for OpenStack Wallaby.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 16 Aug 2021 08:42:02 +0200
+ -- Chris MacNaughton <chris.macnaughton@ubuntu.com>  Wed, 17 Mar 2021 13:29:01 +0000
 
-python-glance-store (2.5.0-1) experimental; urgency=medium
+python-glance-store (2.4.0-0ubuntu1) hirsute; urgency=medium
 
-  * New upstream release.
-  * Fixed (build-)depends for this release.
+  * d/control: Update VCS paths for move to lp:~ubuntu-openstack-dev.
+  * New upstream release for OpenStack Wallaby.
 
- -- Thomas Goirand <zigo@debian.org>  Sun, 14 Mar 2021 16:17:54 +0100
+ -- Chris MacNaughton <chris.macnaughton@ubuntu.com>  Thu, 03 Dec 2020 13:06:14 +0000
 
-python-glance-store (2.3.0-4) unstable; urgency=medium
+python-glance-store (2.3.0-0ubuntu1) groovy; urgency=medium
 
-  * glance-store-common.preinst: remove /etc/glance/rootwrap.conf, if it was
-    an unmodified filed by the glance-common postinst, to avoid dpkg
-    interactive prompting. (Closes: #984613)
+  * New upstream release for OpenStack Victoria.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 10 Mar 2021 10:58:01 +0100
+ -- Chris MacNaughton <chris.macnaughton@canonical.com>  Thu, 03 Sep 2020 07:00:37 +0000
 
-python-glance-store (2.3.0-3) unstable; urgency=medium
+python-glance-store (2.1.0-0ubuntu1) groovy; urgency=medium
 
-  * Correctly install files in /etc/glance.
-  * Standards-Version: 4.5.0.
-  * Use debhelper-compat = 11.
+  * New upstream release for OpenStack Victoria.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 16 Oct 2020 13:52:38 +0200
+ -- Chris MacNaughton <chris.macnaughton@canonical.com>  Fri, 24 Jul 2020 10:02:40 +0000
 
-python-glance-store (2.3.0-2) unstable; urgency=medium
+python-glance-store (2.0.0-0ubuntu1) focal; urgency=medium
 
-  * Uploading to unstable.
-  * Add a debian/salsa-ci.yml.
+  * New upstream release for OpenStack Ussuri.
+  * d/control: Align (Build-)Depends with upstream.
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 14 Oct 2020 23:10:36 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 09 Apr 2020 10:30:08 -0400
 
-python-glance-store (2.3.0-1) experimental; urgency=medium
+python-glance-store (1.1.0-0ubuntu3) focal; urgency=medium
 
-  * New upstream release.
-  * Fixed (build-)depends for this release.
+  * d/python3-glance-store.install: Fix installation of /etc/glance.
+  * d/python3-glance-store.postinst: Added since glance-store installs to
+    /etc/glance/rootwrap.d. Set default ownership and permissions for
+    /etc/<pkg> (LP: #1859422).
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 07 Sep 2020 14:38:18 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 26 Mar 2020 09:33:55 -0400
 
-python-glance-store (2.0.0-2) unstable; urgency=medium
+python-glance-store (1.1.0-0ubuntu2) focal; urgency=medium
 
-  * Uploading to unstable.
+  * d/rules: Install binary and library code with pkgos-dh_auto_install,
+    installing directly to debian/python3-glance-store/usr/.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 08 May 2020 10:56:38 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 03 Feb 2020 15:20:07 -0500
 
-python-glance-store (2.0.0-1) experimental; urgency=medium
+python-glance-store (1.1.0-0ubuntu1) focal; urgency=low
 
-  * New upstream release.
-  * Add python3-boto3 as build-depends.
+  * Merge from Debian unstable.  Remaining changes:
+    - d/control: Enable autopkgtest-pkg-python testsuite.
+    - d/gbp.conf: Retain for gbp and pristine-tar config.
+    - d/watch: Get tarball from tarballs.openstack.org.
+    - d/control: Drop glance-store-common binary packages.
+    - d/control: Breaks/Replaces python3-glance-store -> glance-store-common.
+    - d/python3-glance-store.*: Dropped. No need to update alternatives.
+  * New upstream release for OpenStack Ussuri.
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 06 Apr 2020 17:34:50 +0200
+ -- Sahid Orentino Ferdjaoui <sahid.ferdjaoui@canonical.com>  Thu, 30 Jan 2020 10:41:32 +0100
 
 python-glance-store (1.0.1-2) unstable; urgency=medium
 
@@ -237,6 +263,21 @@ python-glance-store (1.0.0-1) experiment
 
  -- Thomas Goirand <zigo@debian.org>  Tue, 17 Sep 2019 22:12:07 +0200
 
+python-glance-store (1.0.0-0ubuntu1) eoan; urgency=medium
+
+  * New upstream release for OpenStack Train.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 25 Sep 2019 14:08:30 -0400
+
+python-glance-store (0.29.1-0ubuntu1) eoan; urgency=medium
+
+  * New upstream release for OpenStack Train.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/prevent-unicode-object-error-from-zero-byte-read: Dropped. Fixed
+    in new upstream release.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 30 Jul 2019 15:29:04 -0400
+
 python-glance-store (0.28.0-3) unstable; urgency=medium
 
   * Uploading to unstable.
@@ -257,6 +298,39 @@ python-glance-store (0.28.0-1) experimen
 
  -- Thomas Goirand <zigo@debian.org>  Tue, 26 Mar 2019 22:31:47 +0100
 
+python-glance-store (0.28.0-0ubuntu3) eoan; urgency=medium
+
+  * Drop support for Python 2:
+    - d/control: Drop python-glance-store and glance-store-common
+      binary packages.
+    - d/control: Breaks/Replaces python3-glance-store -> glance-store-common.
+    - d/control: Drop BDI's on python-*.
+    - d/rules: Skip install and test of Python 2 module.
+    - d/python3-glance-store.install: Move install of configuration files
+      to Python 3 module.
+
+ -- James Page <james.page@ubuntu.com>  Thu, 11 Jul 2019 07:08:34 +0100
+
+python-glance-store (0.28.0-0ubuntu2) eoan; urgency=medium
+
+  * d/p/prevent-unicode-object-error-from-zero-byte-read: Fix unicode
+    issue (LP: #1805332).
+
+ -- Sahid Orentino Ferdjaoui <sahid.ferdjaoui@canonical.com>  Wed, 24 Apr 2019 13:46:56 +0100
+
+python-glance-store (0.28.0-0ubuntu1) disco; urgency=medium
+
+  * New upstream release for OpenStack Stein.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 11 Mar 2019 14:18:25 -0400
+
+python-glance-store (0.27.0-0ubuntu1) disco; urgency=medium
+
+  * New upstream release for OpenStack Stein.
+  * d/p/drop-doc8.patch: Drop, included upstream.
+
+ -- James Page <james.page@ubuntu.com>  Tue, 20 Nov 2018 10:07:17 +0000
+
 python-glance-store (0.26.1-4) unstable; urgency=medium
 
   * Update patch (already merged into master)
@@ -290,6 +364,34 @@ python-glance-store (0.26.1-1) experimen
 
  -- Thomas Goirand <zigo@debian.org>  Wed, 22 Aug 2018 16:24:14 +0200
 
+python-glance-store (0.26.1-0ubuntu2) cosmic; urgency=medium
+
+  * d/p/drop-doc8.patch: Drop runtime requirement on doc8; its used
+    for style checking of RST documentation so is build time only.
+
+ -- James Page <james.page@ubuntu.com>  Tue, 14 Aug 2018 14:31:58 +0100
+
+python-glance-store (0.26.1-0ubuntu1) cosmic; urgency=medium
+
+  * New upstream point release for OpenStack Rocky.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 10 Aug 2018 15:32:53 -0400
+
+python-glance-store (0.26.0-0ubuntu1) cosmic; urgency=low
+
+  * Merge from Debian unstable.  Remaining changes:
+    - d/control: Enable autopkgtest-pkg-python testsuite.
+    - d/gbp.conf: Retain for gbp and pristine-tar config.
+    - d/watch: Get tarball from tarballs.openstack.org.
+    - d/rules: Skip tests for Py3.7.
+  * New upstream release for OpenStack Rocky.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/rules: Run tests with stestr.
+  * d/p/drop-sphinxcontrib-apidoc.patch: Drop sphinxcontrib.apidoc extension
+    until package is available.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 06 Aug 2018 10:40:13 -0400
+
 python-glance-store (0.23.0-3) unstable; urgency=medium
 
   * Python 3 now has priority over Python 2.
@@ -315,6 +417,18 @@ python-glance-store (0.23.0-1) experimen
 
  -- Thomas Goirand <zigo@debian.org>  Wed, 14 Feb 2018 08:35:38 +0000
 
+python-glance-store (0.23.0-0ubuntu1) bionic; urgency=medium
+
+  * New upstream release.
+  * d/*: wrap-and-sort -bast.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/control: Update Standards-Version to 4.1.2.
+  * d/control: Bump debhelper compat to 10.
+  * d/p/drop-openstackdoctheme.patch: Dropped. No longer needed.
+  * d/p/drop-enum34.patch: Rebased.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 24 Jan 2018 11:57:34 -0500
+
 python-glance-store (0.22.0-2) unstable; urgency=medium
 
   * Only modify /etc/glance if files/dirs exist (Closes: #880087).
@@ -349,6 +463,75 @@ python-glance-store (0.22.0-1) experimen
 
  -- Thomas Goirand <zigo@debian.org>  Sat, 07 Oct 2017 11:22:04 +0200
 
+python-glance-store (0.22.0-0ubuntu1) artful; urgency=medium
+
+  * d/watch: Get tarball from tarballs.openstack.org.
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 15 Aug 2017 16:31:13 -0400
+
+python-glance-store (0.21.0-0ubuntu1) artful; urgency=medium
+
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/drop-enum34.patch: Rebased.
+  * d/p/drop-openstackdoctheme.patch: Temporarily drop openstackdocstheme
+    sphinx extension until sphinx>=1.6.2 is available.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 04 Aug 2017 11:54:15 -0400
+
+python-glance-store (0.20.0-0ubuntu2) zesty; urgency=medium
+
+  * debian/glance-common.install: Fix rootwrap install. 
+
+ -- Chuck Short <zulcss@ubuntu.com>  Mon, 23 Jan 2017 05:20:19 -0500
+
+python-glance-store (0.20.0-0ubuntu1) zesty; urgency=medium
+
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/drop-git-sphinx.patch: Dropped. Fixed upstream.
+  * d/p/drop-enum34.patch: Rebased.
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 19 Jan 2017 12:15:32 -0500
+
+python-glance-store (0.18.0-0ubuntu3) zesty; urgency=medium
+
+  * d/gbp.conf: Update default config.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 04 Nov 2016 08:09:18 -0400
+
+python-glance-store (0.18.0-0ubuntu2) zesty; urgency=medium
+
+  [ Corey Bryant ]
+  * d/control: Add run-time dependency for python-swiftclient (LP: #1604397).
+  * d/p/drop-enum34.patch: Fix python3 test failures.
+
+  [ Thomas Goirand ]
+  * Fixed enum34 runtime depends.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 03 Nov 2016 15:20:09 -0400
+
+python-glance-store (0.18.0-0ubuntu1) yakkety; urgency=medium
+
+  [ James Page ]
+  * d/glance-store-common.*,control,glance_sudoers: Add binary package for
+    shared rootwrap configuration, associated filters and sudoers.d
+    configuration (LP: #1609733).
+
+  [ Corey Bryant ]
+  * New upstream release.
+  * .gitreview: Copy from orig tar ball.
+  * d/gbp.conf: Update debian-branch for Newton.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/drop-git-sphinx.patch: Rebased.
+  * glance_store/tests/unit/test_swift_store.py: Copied from orig tarball.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 02 Sep 2016 13:08:17 -0400
+
 python-glance-store (0.13.1-1) unstable; urgency=medium
 
   * Team upload.
@@ -505,3 +688,4 @@ python-glance-store (0.1.3-1) unstable;
   * Initial release. (Closes: #760537)
 
  -- Thomas Goirand <zigo@debian.org>  Fri, 05 Sep 2014 10:54:04 +0800
+
diff -pruN 4.9.1-2/debian/control 5.0.0-0ubuntu2/debian/control
--- 4.9.1-2/debian/control	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/control	2025-08-19 06:05:40.000000000 +0000
@@ -1,71 +1,66 @@
 Source: python-glance-store
 Section: python
 Priority: optional
-Maintainer: Debian OpenStack <team+openstack@tracker.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Debian OpenStack <openstack-devel@lists.alioth.debian.org>
 Uploaders:
  Thomas Goirand <zigo@debian.org>,
  Corey Bryant <corey.bryant@canonical.com>,
- Michal Arbet <michal.arbet@ultimum.io>,
- Mickael Asseline <mickael@papamica.com>,
 Build-Depends:
- debhelper-compat (= 11),
+ debhelper-compat (= 13),
  dh-python,
  openstack-pkg-tools,
  python3-all,
- python3-pbr,
+ python3-pbr (>= 2.0.0),
  python3-setuptools,
- python3-sphinx,
+ python3-sphinx (>= 2.0.0),
 Build-Depends-Indep:
- python3-boto3,
- python3-cinderclient,
- python3-coverage,
- python3-eventlet,
- python3-fixtures,
+ python3-boto3 (>= 1.9.199),
+ python3-cinderclient (>= 1:4.1.0),
+ python3-coverage (>= 4.0),
+ python3-ddt (>= 1.4.4),
+ python3-debtcollector,
+ python3-doc8 (>= 0.6.0),
+ python3-eventlet (>= 0.18.2),
+ python3-fixtures (>= 3.0.0),
  python3-gridfs,
  python3-hacking,
- python3-httplib2,
- python3-jsonschema,
- python3-keystoneauth1,
- python3-keystoneclient,
- python3-openstackdocstheme,
- python3-os-brick,
- python3-oslo.concurrency,
- python3-oslo.config,
- python3-oslo.i18n,
- python3-oslo.privsep,
- python3-oslo.rootwrap,
- python3-oslo.serialization,
- python3-oslo.utils,
- python3-oslo.vmware,
- python3-oslotest,
+ python3-httplib2 (>= 0.9.1),
+ python3-jsonschema (>= 3.2.0),
+ python3-keystoneauth1 (>= 3.4.0),
+ python3-keystoneclient (>= 1:3.8.0),
+ python3-mock (>= 2.0.0),
+ python3-openstackdocstheme (>= 2.2.1),
+ python3-openstacksdk (>= 0.10.0),
+ python3-os-brick (>= 2.6.0),
+ python3-os-testr (>= 1.0.0),
+ python3-oslo.concurrency (>= 3.26.0),
+ python3-oslo.config (>= 1:5.2.0),
+ python3-oslo.i18n (>= 3.15.3),
+ python3-oslo.privsep (>= 1.23.0),
+ python3-oslo.rootwrap (>= 5.8.0),
+ python3-oslo.serialization (>= 2.18.0),
+ python3-oslo.utils (>= 4.7.0),
+ python3-oslo.vmware (>= 3.6.0),
+ python3-oslotest (>= 1:3.2.0),
  python3-pymongo,
- python3-requests,
- python3-requests-mock,
- python3-retrying,
- python3-sphinxcontrib.apidoc,
- python3-stestr,
- python3-stevedore,
- python3-subunit,
- python3-swiftclient,
- python3-testscenarios,
- python3-testtools,
+ python3-reno,
+ python3-requests (>= 2.14.2),
+ python3-requests-mock (>= 1.2.0),
+ python3-retrying (>= 1.3.3),
+ python3-sphinxcontrib.apidoc (>= 0.2.0),
+ python3-stestr (>= 2.0.0),
+ python3-stevedore (>= 1:1.20.0),
+ python3-subunit (>= 1.0.0),
+ python3-swiftclient (>= 1:3.2.0),
+ python3-testrepository (>= 0.0.18),
+ python3-testscenarios (>= 0.4),
+ python3-testtools (>= 2.2.0),
  subunit,
-Standards-Version: 4.5.0
-Vcs-Browser: https://salsa.debian.org/openstack-team/libs/python-glance-store
-Vcs-Git: https://salsa.debian.org/openstack-team/libs/python-glance-store.git
-Homepage: https://github.com/openstack/glance_store
-
-Package: glance-store-common
-Architecture: all
-Depends:
- ${misc:Depends},
-Description: OpenStack Image Service store library - common files
- The Glance project provides services for discovering, registering, and
- retrieving virtual machine images over the cloud. They may be stand-alone
- services, or may be used to deliver images from object stores, such as
- OpenStack's Swift service, to Nova's compute nodes.
- .
- This package contains shared configuration files for the Glance's stores.
+Standards-Version: 4.6.1
+Vcs-Git: https://git.launchpad.net/~ubuntu-openstack-dev/ubuntu/+source/python-glanceclient
+Homepage: https://opendev.org/openstack/glance_store
+Testsuite: autopkgtest-pkg-python
 
 Package: python-glance-store-doc
 Section: doc
@@ -84,28 +79,34 @@ Description: OpenStack Image Service sto
 Package: python3-glance-store
 Architecture: all
 Depends:
- glance-store-common (= ${binary:Version}),
- python3-cinderclient,
- python3-eventlet,
+ python3-cinderclient (>= 1:3.3.0),
+ python3-ddt (>= 1.4.4),
+ python3-debtcollector,
+ python3-eventlet (>= 0.18.2),
  python3-httplib2,
- python3-jsonschema,
- python3-keystoneauth1,
- python3-keystoneclient,
- python3-os-brick,
- python3-oslo.concurrency,
- python3-oslo.config,
- python3-oslo.i18n,
- python3-oslo.privsep,
- python3-oslo.rootwrap,
- python3-oslo.serialization,
- python3-oslo.utils,
- python3-oslo.vmware,
- python3-pbr,
- python3-requests,
- python3-stevedore,
+ python3-jsonschema (>= 3.2.0),
+ python3-keystoneauth1 (>= 3.4.0),
+ python3-keystoneclient (>= 1:3.8.0),
+ python3-os-brick (>= 2.2.0),
+ python3-oslo.concurrency (>= 3.26.0),
+ python3-oslo.config (>= 1:5.2.0),
+ python3-oslo.i18n (>= 3.15.3),
+ python3-oslo.privsep (>= 1.23.0),
+ python3-oslo.rootwrap (>= 5.8.0),
+ python3-oslo.serialization (>= 2.18.0),
+ python3-oslo.utils (>= 4.7.0),
+ python3-oslo.vmware (>= 3.6.0),
+ python3-pbr (>= 2.0.0),
+ python3-requests (>= 2.14.2),
+ python3-retrying (>= 1.3.3),
+ python3-stevedore (>= 1:1.20.0),
  python3-swiftclient,
  ${misc:Depends},
  ${python3:Depends},
+Breaks:
+ glance-store-common (<< 0.28.0-0ubuntu3~),
+Replaces:
+ glance-store-common (<< 0.28.0-0ubuntu3~),
 Description: OpenStack Image Service store library - Python 3.x
  The Glance project provides services for discovering, registering, and
  retrieving virtual machine images over the cloud. They may be stand-alone
diff -pruN 4.9.1-2/debian/copyright 5.0.0-0ubuntu2/debian/copyright
--- 4.9.1-2/debian/copyright	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/copyright	2025-08-19 06:05:40.000000000 +0000
@@ -17,7 +17,6 @@ License: Apache-2
 Files: debian/*
 Copyright: (c) 2014-2016, Thomas Goirand <zigo@debian.org>
            (c) 2018-2019, Michal Arbet <michal.arbet@ultimum.io>
-           (c) 2021 Mickael Asseline <mickael@papamica.com>
 License: Apache-2
 
 License: Apache-2
diff -pruN 4.9.1-2/debian/gbp.conf 5.0.0-0ubuntu2/debian/gbp.conf
--- 4.9.1-2/debian/gbp.conf	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/gbp.conf	2025-08-19 06:05:40.000000000 +0000
@@ -0,0 +1,9 @@
+[DEFAULT]
+debian-branch = master
+upstream-tag = %(version)s
+pristine-tar = True
+upstream-branch = upstream-flamingo
+
+[buildpackage]
+export-dir = ../build-area
+prebuild = [ ! -f .launchpad.yaml ] || rm .launchpad.yaml
diff -pruN 4.9.1-2/debian/glance-store-common.install 5.0.0-0ubuntu2/debian/glance-store-common.install
--- 4.9.1-2/debian/glance-store-common.install	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/glance-store-common.install	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-debian/glance_sudoers /etc/sudoers.d
diff -pruN 4.9.1-2/debian/glance-store-common.postinst 5.0.0-0ubuntu2/debian/glance-store-common.postinst
--- 4.9.1-2/debian/glance-store-common.postinst	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/glance-store-common.postinst	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "configure" ] ; then
-	if [ -f /etc/glance/rootwrap.conf ] ; then
-		chown root:root /etc/glance/rootwrap.conf
-	fi
-
-	if [ -d /etc/glance/rootwrap.d ] ; then
-		chown -R root:root /etc/glance/rootwrap.d
-		chmod 0755 /etc/glance/rootwrap.d
-	fi
-
-	if [ -f /etc/sudoers.d/glance_sudoers ] ; then
-		chmod 0440 /etc/sudoers.d/glance_sudoers
-	fi
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 4.9.1-2/debian/glance-store-common.preinst 5.0.0-0ubuntu2/debian/glance-store-common.preinst
--- 4.9.1-2/debian/glance-store-common.preinst	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/glance-store-common.preinst	1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "${1}" = "install" ] || [ "${1}" = "upgrade" ] ; then
-	# The file /etc/glance/rootwrap.conf in buster was copied from
-	# /usr/share/glance-common/rootwrap.conf from the glance-common
-	# package during postinst. In Bullseye, it becomes a CONFFILE
-	# owned by the glance-store-common package. To avoid prompting
-	# during upgrade from Buster to Bullseye, we therefore need to
-	# get the file away before installing glance-store-common,
-	# otherwise dpkg will prompt the user interactively.
-	#
-	# Of course, this wont be needed in Bookworms anymore.
-	if [ -e /etc/glance/rootwrap.conf ] ; then
-		# We only remove the file if it wasn't manually modified
-		# by the user (in which case dpkg prompting is the correct
-		# thing to do). So we just use the MD5 to see if it's the
-		# same file.
-		MD5=$(md5sum /etc/glance/rootwrap.conf | awk '{print $1}')
-		if [ "${MD5}" = "38f96ec95f09ffb192ee2febc6f771a1" ] ; then
-			rm /etc/glance/rootwrap.conf
-		fi
-	fi
-fi
diff -pruN 4.9.1-2/debian/glance_sudoers 5.0.0-0ubuntu2/debian/glance_sudoers
--- 4.9.1-2/debian/glance_sudoers	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/glance_sudoers	2025-08-19 10:21:03.000000000 +0000
@@ -1,3 +1 @@
-Defaults:glance !requiretty
-
 glance ALL = (root) NOPASSWD: /usr/bin/glance-rootwrap /etc/glance/rootwrap.conf *
diff -pruN 4.9.1-2/debian/python3-glance-store.install 5.0.0-0ubuntu2/debian/python3-glance-store.install
--- 4.9.1-2/debian/python3-glance-store.install	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/python3-glance-store.install	2025-08-19 06:05:40.000000000 +0000
@@ -1 +1,2 @@
-/usr
+debian/glance_sudoers /etc/sudoers.d
+etc/glance/* /etc/glance/
diff -pruN 4.9.1-2/debian/python3-glance-store.postinst 5.0.0-0ubuntu2/debian/python3-glance-store.postinst
--- 4.9.1-2/debian/python3-glance-store.postinst	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/python3-glance-store.postinst	2025-08-19 06:05:40.000000000 +0000
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+GLANCE_UID=64062
+GLANCE_GID=64062
+
+if [ "$1" = "configure" ]
+then
+    if ! getent group glance > /dev/null 2>&1
+    then
+        addgroup --quiet --system \
+            --gid $GLANCE_GID glance 2>/dev/null
+    fi
+    if ! getent passwd glance > /dev/null 2>&1
+    then
+        adduser --quiet --system \
+            --home /var/lib/glance \
+            --no-create-home \
+            --uid $GLANCE_UID \
+            --gid $GLANCE_GID \
+            --shell /bin/false glance 2>/dev/null
+    fi
+
+    find /etc/glance -exec chown root:glance "{}" +
+    find /etc/glance -type f -exec chmod 0640 "{}" + -o -type d -exec chmod 0750 "{}" +
+
+    find /etc/glance/rootwrap.d -exec chown root:root "{}" +
+    find /etc/glance/rootwrap.d -type f -exec chmod 0644 "{}" + -o -type d -exec chmod 0755 "{}" +
+fi
+
+#DEBHELPER#
diff -pruN 4.9.1-2/debian/python3-glance-store.postrm 5.0.0-0ubuntu2/debian/python3-glance-store.postrm
--- 4.9.1-2/debian/python3-glance-store.postrm	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/python3-glance-store.postrm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] || [ "$1" = "disappear" ] ; then
-	update-alternatives --remove glance-rootwrap /usr/bin/python3-glance-rootwrap
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 4.9.1-2/debian/python3-glance-store.prerm 5.0.0-0ubuntu2/debian/python3-glance-store.prerm
--- 4.9.1-2/debian/python3-glance-store.prerm	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/python3-glance-store.prerm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] ; then
-	update-alternatives --remove glance-rootwrap /usr/bin/python3-glance-rootwrap
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 4.9.1-2/debian/rules 5.0.0-0ubuntu2/debian/rules
--- 4.9.1-2/debian/rules	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/rules	2025-08-19 06:05:40.000000000 +0000
@@ -11,25 +11,20 @@ include /usr/share/openstack-pkg-tools/p
 	dh $@ --buildsystem=pybuild --with python3,sphinxdoc
 
 override_dh_auto_clean:
-	rm -rf build .stestr *.egg-info
+	rm -rf build .stestr
 	find . -iname '*.pyc' -delete
 	for i in $$(find . -type d -iname __pycache__) ; do rm -rf $$i ; done
-	rm -rf doc/source/reference/api
 
 override_dh_auto_build:
 	echo "Do nothing..."
 
 override_dh_auto_install:
-	for i in $(PYTHON3S) ; do \
-		python3 setup.py install -f --install-layout=deb --root=$(CURDIR)/debian/tmp ; \
-	done
+	pkgos-dh_auto_install --no-py2
+	rm -rf $(CURDIR)/debian/python3-glance-store/usr/etc
+
 ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS)))
-	PYTHONPATH=$(CURDIR)/debian/tmp/usr/lib/python3/dist-packages pkgos-dh_auto_test --no-py2
+	PYTHONPATH=$(CURDIR)/debian/python3-glance-store/usr/lib/python3/dist-packages pkgos-dh_auto_test --no-py2
 endif
-	mkdir -p $(CURDIR)/debian/glance-store-common/etc/glance
-	mv $(CURDIR)/debian/tmp/usr/etc/glance/* $(CURDIR)/debian/glance-store-common/etc/glance
-	rmdir $(CURDIR)/debian/tmp/usr/etc/glance
-	rmdir $(CURDIR)/debian/tmp/usr/etc
 
 override_dh_auto_test:
 	echo "Do nothing..."
diff -pruN 4.9.1-2/debian/salsa-ci.yml 5.0.0-0ubuntu2/debian/salsa-ci.yml
--- 4.9.1-2/debian/salsa-ci.yml	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/salsa-ci.yml	1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-include:
-  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
-  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
diff -pruN 4.9.1-2/debian/source/options 5.0.0-0ubuntu2/debian/source/options
--- 4.9.1-2/debian/source/options	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/source/options	2025-08-19 06:05:40.000000000 +0000
@@ -1 +1,2 @@
 extend-diff-ignore = "^[^/]*[.]egg-info/"
+extend-diff-ignore = "^.launchpad.yaml"
diff -pruN 4.9.1-2/debian/tests/control 5.0.0-0ubuntu2/debian/tests/control
--- 4.9.1-2/debian/tests/control	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/tests/control	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-Tests: unittests
-Depends:
- @,
- @builddeps@,
-Restrictions: allow-stderr needs-root
diff -pruN 4.9.1-2/debian/tests/unittests 5.0.0-0ubuntu2/debian/tests/unittests
--- 4.9.1-2/debian/tests/unittests	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/tests/unittests	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-set -e
-
-pkgos-dh_auto_test --no-py2 'glance_store\.tests\.unit\.(?!.*cinder\.test_base\.TestConnectorBase\.test_factory_3.*)'
diff -pruN 4.9.1-2/debian/upstream/signing-key.asc 5.0.0-0ubuntu2/debian/upstream/signing-key.asc
--- 4.9.1-2/debian/upstream/signing-key.asc	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/upstream/signing-key.asc	2025-08-19 06:05:40.000000000 +0000
@@ -0,0 +1,34 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEZ92jlhYJKwYBBAHaRw8BAQdAnSMr01EpuQHlcTQ8c0ENVDFs9mi/TdWB0IlG
+ZF1eC2S0Qk9wZW5TdGFjayBJbmZyYSAoMjAyNS4yL0ZsYW1pbmdvIEN5Y2xlKSA8
+aW5mcmEtcm9vdEBvcGVuc3RhY2sub3JnPoiWBBMWCAA+FiEExxsAfvl4h/2PtjZc
+60/W1hjmIYEFAmfdo5YCGwMFCQFj9QAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AA
+CgkQ60/W1hjmIYElLAEAkMjANVr+kVjZGp8KtliT+ySFAqoCQceuscYt7WmeD4wA
+/2gHNfFDJwkWn9JY9mCR2y7gwf6skTWl3ssPogTa84wDiHUEEBYIAB0WIQQiKE9p
+2ezN8994GXkccRrxk/+OVAUCZ92k6wAKCRAccRrxk/+OVMQGAQD0X/Eow2mK/YzZ
+rMO60g2KI767/rnKJWKFUTCZCfswxwD/WxuGjGRB98RZ9IbCcmaUvRqHf9812h60
+/RCoB4AtiwSJAjMEEAEKAB0WIQSXrklvwC3sn8NTsudI+ZYRQ0lYKQUCZ92vKwAK
+CRBI+ZYRQ0lYKdthD/wJh0uxw05WsmFwjuds82JdnH9ow3OdG/0bhds8eEvgYuQe
+ZEQ9/RC5hJ+SiV+/zclIaG+xYHW3VkZUgOmmLxRzmqFbWbDm5yKp7jTqM2zYB4Jx
+EiLB4dWHZFmrcqfkJ06nXVMjGkj73N+DqHWQ6hleaiE7tcbI++w1AN7niL0rW008
+iP8IHoWLh2dJxQlcheVdjCe0jEU3qO8KxhUTeARPD/Vp1CpJWlq9vWs9/bweMrtj
+FsQwxBiZcQ/0zXDnQFUKpbNDFjQZnjmmwTqhopquL5e5mZWr0NussI20JXyZHj7T
+N5ikDAFPf9iM1Apb+/g9njGUgYFEOgEJuDr1oLolZ+9+7uZrKGD1gmdY7pVG12Xn
+2QJ3rft/Wy8Obac+TdA+UoEYQu4LOUpUOmPOcXE/8/fTxybkQGOZm1Ufaddz+6ee
+uHBbIaxI1kh5MrxH5cIaEkvdjOGg+bMyq7C8CE8WgSEN/JiupEZYgDduOSuqGHDp
++9ydEkanNjGN+K4rXJ7ABBv9freINx5kmCAaDzXeIAL8n1/Rzd6Z/acOlC9omDM0
+mYKKIfLMp6Rp7SKnB37Tp0dKGP4r/SJsx5Sxn7XrktVJ1ht5ByipDD6VBN3+OQPx
+56pRLDCk9EFDjbOW0iKzyPx+Nya5G9CN9AqQXe1MlHsFn+q7DEUSmlGZfvtjN7g4
+BGfdo5YSCisGAQQBl1UBBQEBB0DHSvmmZUEZ94olzKZSHa2HBCWhrhOVNFn/0ag8
+KyY5fQMBCAeIfgQYFggAJhYhBMcbAH75eIf9j7Y2XOtP1tYY5iGBBQJn3aOWAhsM
+BQkBY/UAAAoJEOtP1tYY5iGB6XcA+wY0JUi2ZUqH0CRs4EfS6VML/7u08g8ZByN4
+DZ2htqOGAQDmGHHjpMhKz04eDXLpNO6UZ/Q6LnqEXztW8eBXVtiZALgzBGfdpHYW
+CSsGAQQB2kcPAQEHQKH/4Td8MRK/9UxGyPqWWaZl88m4xE48XM4kP6w3asRViO8E
+GBYIACAWIQTHGwB++XiH/Y+2NlzrT9bWGOYhgQUCZ92kdgIbAgCBCRDrT9bWGOYh
+gXYgBBkWCAAdFiEE3cFPzrMpT3Q4I7HG9zFcLOa3NF0FAmfdpHYACgkQ9zFcLOa3
+NF1xqwEA3muioM6tJtSbiCUCDau2QnalBkfov/A2FFIxvnyHbH0A/051M0O09Tcl
+E7tAieH8W63Jhg3n/GzKl36hXqh3ANML8kIA/0eu6JgK+F0s8iiy+sQecTD7W38B
+A8CSZ29ANdlMwzf7AP9araqMvKRpTMAzhQ+1Eluh8FmXQhzeZDhlIZ8DQDQ/CQ==
+=FVKc
+-----END PGP PUBLIC KEY BLOCK-----
diff -pruN 4.9.1-2/debian/watch 5.0.0-0ubuntu2/debian/watch
--- 4.9.1-2/debian/watch	2025-03-28 07:30:42.000000000 +0000
+++ 5.0.0-0ubuntu2/debian/watch	2025-08-19 06:05:40.000000000 +0000
@@ -1,3 +1,3 @@
-version=4
-opts="mode=git,uversionmangle=s/\.0rc/~rc/;s/\.0b1/~b1/;s/\.0b2/~b2/;s/\.0b3/~b3/" \
-https://github.com/openstack/glance_store refs/tags/(\d[brc\d\.]+)
+version=3
+opts=uversionmangle=s/\.(b|rc)/~$1/,pgpsigurlmangle=s/$/.asc/ \
+    http://tarballs.openstack.org/glance_store/ glance_store-(\d.*)\.tar\.gz
diff -pruN 4.9.1-2/glance_store/_drivers/cinder/store.py 5.0.0-0ubuntu2/glance_store/_drivers/cinder/store.py
--- 4.9.1-2/glance_store/_drivers/cinder/store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/cinder/store.py	2025-07-10 09:13:16.000000000 +0000
@@ -493,7 +493,8 @@ class Store(glance_store.driver.Store):
         self.mount = importlib.import_module('glance_store.common.fs_mount')
         self._set_url_prefix()
         if self.backend_group:
-            self.store_conf = getattr(self.conf, self.backend_group)
+            self.store_conf = glance_store.driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
         else:
             self.store_conf = self.conf.glance_store
         self.volume_api = cinder_utils.API()
@@ -949,6 +950,14 @@ class Store(glance_store.driver.Store):
                 return
             f.write(write_props.buf)
             write_props.bytes_written += len(write_props.buf)
+            # Check if total written exceeds image_size
+            if (write_props.image_size and
+                    write_props.bytes_written > write_props.image_size):
+                raise exceptions.Invalid(
+                    _("Size exceeds: expected %(expected)d "
+                      "bytes, got %(actual)d bytes") %
+                    {'expected': write_props.image_size,
+                     'actual': write_props.bytes_written})
 
     def _offline_extend(self, client, volume, write_props):
         while write_props.need_extend:
@@ -1077,6 +1086,23 @@ class Store(glance_store.driver.Store):
                                       '%(volume_id)s.'),
                                   {'volume_id': volume.id})
 
+        if image_size != 0 and write_props.bytes_written != image_size:
+            # Delete the partial volume
+            try:
+                volume.delete()
+                LOG.info(_LI("Partial volume %(volume_id)s deleted after "
+                             "exceeding image_size."),
+                         {'volume_id': volume.id})
+            except Exception:
+                LOG.exception(_LE('Failed to delete of volume '
+                                  '%(volume_id)s.'),
+                              {'volume_id': volume.id})
+            # Raise an exception with image size info
+            raise exceptions.Invalid(_(
+                "Size mismatch: expected %(expected)d  bytes, got %(actual)d "
+                "bytes") % {'expected': image_size,
+                            'actual': write_props.bytes_written})
+
         if write_props.image_size == 0:
             metadata.update({'image_size': str(write_props.bytes_written)})
             volume.update_all_metadata(metadata)
diff -pruN 4.9.1-2/glance_store/_drivers/filesystem.py 5.0.0-0ubuntu2/glance_store/_drivers/filesystem.py
--- 4.9.1-2/glance_store/_drivers/filesystem.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/filesystem.py	2025-07-10 09:13:16.000000000 +0000
@@ -70,6 +70,14 @@ Related options:
 
 """),
     cfg.MultiStrOpt('filesystem_store_datadirs',
+                    deprecated_for_removal=True,
+                    deprecated_since='Flamingo',
+                    deprecated_reason="""
+Users willing to use multiple data directories should configure multiple
+filesystem stores instead of using filesystem_store_datadirs.
+
+This option is scheduled for removal in the H development cycle.
+""",
                     help="""
 List of directories and their priorities to which the filesystem
 backend store writes images.
@@ -285,6 +293,14 @@ class Store(glance_store.driver.Store):
     OPTIONS = _FILESYSTEM_CONFIGS
     FILESYSTEM_STORE_METADATA = None
 
+    def __init__(self, *args, **kargs):
+        super(Store, self).__init__(*args, **kargs)
+        if self.backend_group:
+            self.store_conf = glance_store.driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
+        else:
+            self.store_conf = self.conf.glance_store
+
     def get_schemes(self):
         return ('file', 'filesystem')
 
@@ -311,11 +327,7 @@ class Store(glance_store.driver.Store):
         :datadir is a directory path in which glance writes image files.
         """
 
-        if self.backend_group:
-            fstore_perm = getattr(
-                self.conf, self.backend_group).filesystem_store_file_perm
-        else:
-            fstore_perm = self.conf.glance_store.filesystem_store_file_perm
+        fstore_perm = self.store_conf.filesystem_store_file_perm
 
         if fstore_perm <= 0:
             return
@@ -421,19 +433,14 @@ class Store(glance_store.driver.Store):
         this method. If the store was not able to successfully configure
         itself, it should raise `exceptions.BadStoreConfiguration`
         """
-        if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
-        else:
-            store_conf = self.conf.glance_store
-
-        fdir = store_conf.filesystem_store_datadir
-        fdirs = store_conf.filesystem_store_datadirs
-        fstore_perm = store_conf.filesystem_store_file_perm
-        meta_file = store_conf.filesystem_store_metadata_file
+        fdir = self.store_conf.filesystem_store_datadir
+        fdirs = self.store_conf.filesystem_store_datadirs
+        fstore_perm = self.store_conf.filesystem_store_file_perm
+        meta_file = self.store_conf.filesystem_store_metadata_file
 
-        self.thin_provisioning = store_conf.\
+        self.thin_provisioning = self.store_conf.\
             filesystem_thin_provisioning
-        self.chunk_size = store_conf.filesystem_store_chunk_size
+        self.chunk_size = self.store_conf.filesystem_store_chunk_size
         self.READ_CHUNKSIZE = self.chunk_size
         self.WRITE_CHUNKSIZE = self.READ_CHUNKSIZE
 
@@ -745,6 +752,14 @@ class Store(glance_store.driver.Store):
             with open(filepath, 'wb') as f:
                 for buf in utils.chunkreadable(image_file,
                                                self.WRITE_CHUNKSIZE):
+                    actual_to_write = bytes_written + len(buf)
+                    if image_size != 0 and actual_to_write > image_size:
+                        raise glance_store.Invalid(
+                            _("Size exceeds: expected "
+                              "%(expected)d "
+                              "bytes, got %(actual)d bytes") %
+                            {'expected': image_size,
+                             'actual': actual_to_write})
                     bytes_written += len(buf)
                     os_hash_value.update(buf)
                     checksum.update(buf)
@@ -766,6 +781,15 @@ class Store(glance_store.driver.Store):
             with excutils.save_and_reraise_exception():
                 self._delete_partial(filepath, image_id)
 
+        # Final size check after reading all chunks
+        if image_size != 0 and bytes_written != image_size:
+            # Cleanup and raise exception after write size mismatch
+            self._delete_partial(filepath, image_id)
+            message = (_("Size mismatch: expected %(expected)d bytes, "
+                         "got %(actual)d bytes") %
+                       {'expected': image_size, 'actual': bytes_written})
+            raise glance_store.Invalid(message=message)
+
         hash_hex = os_hash_value.hexdigest()
         checksum_hex = checksum.hexdigest()
         metadata = self._get_metadata(filepath)
@@ -777,11 +801,7 @@ class Store(glance_store.driver.Store):
                    'checksum_hex': checksum_hex,
                    'hash_hex': hash_hex})
 
-        if self.backend_group:
-            fstore_perm = getattr(
-                self.conf, self.backend_group).filesystem_store_file_perm
-        else:
-            fstore_perm = self.conf.glance_store.filesystem_store_file_perm
+        fstore_perm = self.store_conf.filesystem_store_file_perm
 
         if fstore_perm > 0:
             perm = int(str(fstore_perm), 8)
diff -pruN 4.9.1-2/glance_store/_drivers/http.py 5.0.0-0ubuntu2/glance_store/_drivers/http.py
--- 4.9.1-2/glance_store/_drivers/http.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/http.py	2025-07-10 09:13:16.000000000 +0000
@@ -339,7 +339,8 @@ class Store(glance_store.driver.Store):
             self.session = requests.Session()
 
         if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
+            store_conf = glance_store.driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
         else:
             store_conf = self.conf.glance_store
 
diff -pruN 4.9.1-2/glance_store/_drivers/rbd.py 5.0.0-0ubuntu2/glance_store/_drivers/rbd.py
--- 4.9.1-2/glance_store/_drivers/rbd.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/rbd.py	2025-07-10 09:13:16.000000000 +0000
@@ -282,6 +282,14 @@ class Store(driver.Store):
 
     EXAMPLE_URL = "rbd://<FSID>/<POOL>/<IMAGE>/<SNAP>"
 
+    def __init__(self, *args, **kargs):
+        super(Store, self).__init__(*args, **kargs)
+        if self.backend_group:
+            self.store_conf = driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
+        else:
+            self.store_conf = self.conf.glance_store
+
     def get_schemes(self):
         return ('rbd',)
 
@@ -295,11 +303,7 @@ class Store(driver.Store):
     def get_connection(self, conffile, rados_id):
         client = rados.Rados(conffile=conffile, rados_id=rados_id)
 
-        if self.backend_group:
-            timeout = getattr(self.conf,
-                              self.backend_group).rados_connect_timeout
-        else:
-            timeout = self.conf.glance_store.rados_connect_timeout
+        timeout = self.store_conf.rados_connect_timeout
 
         if timeout >= 0:
             t = str(timeout)
@@ -339,23 +343,11 @@ class Store(driver.Store):
                                                    reason=reason)
 
         try:
-            if self.backend_group:
-                chunk = getattr(self.conf,
-                                self.backend_group).rbd_store_chunk_size
-                pool = getattr(self.conf, self.backend_group).rbd_store_pool
-                user = getattr(self.conf, self.backend_group).rbd_store_user
-                conf_file = getattr(self.conf,
-                                    self.backend_group).rbd_store_ceph_conf
-                thin_provisioning = getattr(self.conf,
-                                            self.backend_group).\
-                    rbd_thin_provisioning
-            else:
-                chunk = self.conf.glance_store.rbd_store_chunk_size
-                pool = self.conf.glance_store.rbd_store_pool
-                user = self.conf.glance_store.rbd_store_user
-                conf_file = self.conf.glance_store.rbd_store_ceph_conf
-                thin_provisioning = \
-                    self.conf.glance_store.rbd_thin_provisioning
+            chunk = self.store_conf.rbd_store_chunk_size
+            pool = self.store_conf.rbd_store_pool
+            user = self.store_conf.rbd_store_user
+            conf_file = self.store_conf.rbd_store_ceph_conf
+            thin_provisioning = self.store_conf.rbd_thin_provisioning
 
             self.thin_provisioning = thin_provisioning
             self.chunk_size = chunk * units.Mi
@@ -613,6 +605,14 @@ class Store(driver.Store):
                                                               bytes_written,
                                                               chunk_length)
                             bytes_written += chunk_length
+                            # Check if writing this chunk exceeds the
+                            # image_size
+                            if image_size != 0 and bytes_written > image_size:
+                                raise exceptions.Invalid(
+                                    _("Size exceeds: expected %(expected)d "
+                                      "bytes, got %(actual)d bytes") %
+                                    {'expected': image_size,
+                                     'actual': bytes_written})
                             if not (self.thin_provisioning and not any(chunk)):
                                 image.write(chunk, offset)
                             offset += chunk_length
@@ -643,6 +643,23 @@ class Store(driver.Store):
                         pass
 
                     raise exceptions.StorageFull(message=log_msg)
+                except rbd.IncompleteWriteError as exc:
+                    log_msg = (_LE("Failed to store image %(img_name)s "
+                                   "image data exceeded the expected size. "
+                                   "Store Exception %(store_exc)s") %
+                               {'img_name': image_name,
+                                'store_exc': exc})
+                    LOG.error(log_msg)
+
+                    # Delete image if one was created
+                    try:
+                        target_pool = loc.pool or self.pool
+                        self._delete_image(target_pool, loc.image,
+                                           loc.snapshot)
+                    except exceptions.NotFound:
+                        pass
+
+                    raise exceptions.Invalid(message=log_msg)
                 except Exception as exc:
                     log_msg = (_LE("Failed to store image %(img_name)s "
                                    "Store Exception %(store_exc)s") %
@@ -660,9 +677,20 @@ class Store(driver.Store):
 
                     raise exc
 
-        # Make sure we send back the image size whether provided or inferred.
-        if image_size == 0:
-            image_size = bytes_written
+        # If actual bytes written are less than image_size
+        # (when image_size != 0), update accordingly
+        if image_size != 0 and bytes_written != image_size:
+            # Delete image if one was created
+            try:
+                self._delete_image(loc.pool or self.pool, loc.image,
+                                   loc.snapshot)
+            except exceptions.NotFound:
+                pass
+
+            raise exceptions.Invalid(_(
+                "Size mismatch: expected %(expected)d "
+                "bytes, got %(actual)d bytes") % {
+                'expected': image_size, 'actual': bytes_written})
 
         # Add store backend information to location metadata
         metadata = {}
@@ -670,7 +698,7 @@ class Store(driver.Store):
             metadata['store'] = self.backend_group
 
         return (loc.get_uri(),
-                image_size,
+                bytes_written,
                 checksum.hexdigest(),
                 os_hash_value.hexdigest(),
                 metadata)
diff -pruN 4.9.1-2/glance_store/_drivers/s3.py 5.0.0-0ubuntu2/glance_store/_drivers/s3.py
--- 4.9.1-2/glance_store/_drivers/s3.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/s3.py	2025-07-10 09:13:16.000000000 +0000
@@ -15,6 +15,7 @@
 
 """Storage backend for S3 or Storage Servers that follow the S3 Protocol"""
 
+from concurrent import futures
 import io
 import logging
 import math
@@ -32,7 +33,6 @@ except ImportError:
     boto_exceptions = None
     boto_utils = None
 
-import eventlet
 from oslo_config import cfg
 from oslo_utils import encodeutils
 from oslo_utils import units
@@ -465,7 +465,8 @@ class Store(glance_store.driver.Store):
 
     def _option_get(self, param):
         if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
+            store_conf = glance_store.driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
         else:
             store_conf = self.conf.glance_store
 
@@ -648,7 +649,8 @@ class Store(glance_store.driver.Store):
                                             key=key,
                                             loc=loc,
                                             hashing_algo=hashing_algo,
-                                            verifier=verifier)
+                                            verifier=verifier,
+                                            image_size=image_size)
 
             return self._add_multipart(s3_client=s3_client,
                                        image_file=image_file,
@@ -663,7 +665,7 @@ class Store(glance_store.driver.Store):
         raise exceptions.Duplicate(image=key)
 
     def _add_singlepart(self, s3_client, image_file, bucket, key, loc,
-                        hashing_algo, verifier):
+                        hashing_algo, verifier, image_size):
         """Stores an image file with a single part upload to S3 backend.
 
         :param s3_client: An object with credentials to connect to S3
@@ -674,6 +676,8 @@ class Store(glance_store.driver.Store):
                     from glance_store.location.get_location_from_uri()
         :param hashing_algo: A hashlib algorithm identifier (string)
         :param verifier: An object used to verify signatures for images
+        :param image_size: The size of the image data to write,
+                           in bytes
         :returns: tuple of: (1) URL in backing store, (2) bytes written,
                   (3) checksum, (4) multihash value, and (5) a dictionary
                   with storage system specific information
@@ -681,15 +685,28 @@ class Store(glance_store.driver.Store):
         os_hash_value = utils.get_hasher(hashing_algo, False)
         checksum = utils.get_hasher('md5', False)
         image_data = b''
-        image_size = 0
+        total_bytes = 0
         for chunk in utils.chunkreadable(image_file, self.WRITE_CHUNKSIZE):
+            total_bytes += len(chunk)
+            if image_size != 0 and total_bytes > image_size:
+                # Size exceeded, abort upload
+                raise glance_store.Invalid(
+                    _("Size exceeds: expected %(expected)d bytes, "
+                      "got %(actual)d bytes") %
+                    {'expected': image_size, 'actual': total_bytes})
             image_data += chunk
-            image_size += len(chunk)
             os_hash_value.update(chunk)
             checksum.update(chunk)
             if verifier:
                 verifier.update(chunk)
 
+        # Final size check after reading all chunks
+        if image_size != 0 and total_bytes != image_size:
+            raise glance_store.Invalid(
+                _("Size mismatch: expected %(expected)d bytes, "
+                  "got %(actual)d bytes") %
+                {'expected': image_size, 'actual': total_bytes})
+
         s3_client.put_object(Body=image_data,
                              Bucket=bucket,
                              Key=key)
@@ -703,9 +720,9 @@ class Store(glance_store.driver.Store):
 
         LOG.debug("Wrote %(size)d bytes to S3 key named %(key)s "
                   "with checksum %(checksum)s",
-                  {'size': image_size, 'key': key, 'checksum': checksum_hex})
+                  {'size': total_bytes, 'key': key, 'checksum': checksum_hex})
 
-        return loc.get_uri(), image_size, checksum_hex, hash_hex, metadata
+        return loc.get_uri(), total_bytes, checksum_hex, hash_hex, metadata
 
     def _add_multipart(self, s3_client, image_file, image_size, bucket,
                        key, loc, hashing_algo, verifier):
@@ -726,71 +743,98 @@ class Store(glance_store.driver.Store):
         os_hash_value = utils.get_hasher(hashing_algo, False)
         checksum = utils.get_hasher('md5', False)
         pool_size = self.s3_store_thread_pools
-        pool = eventlet.greenpool.GreenPool(size=pool_size)
-        mpu = s3_client.create_multipart_upload(Bucket=bucket, Key=key)
-        upload_id = mpu['UploadId']
-        LOG.debug("Multipart initiate key=%(key)s, UploadId=%(UploadId)s",
-                  {'key': key, 'UploadId': upload_id})
-        cstart = 0
-        plist = []
-
-        chunk_size = int(math.ceil(float(image_size) / MAX_PART_NUM))
-        write_chunk_size = max(self.s3_store_large_object_chunk_size,
-                               chunk_size)
-        it = utils.chunkreadable(image_file, self.WRITE_CHUNKSIZE)
-        buffered_chunk = b''
-        while True:
-            try:
-                buffered_clen = len(buffered_chunk)
-                if buffered_clen < write_chunk_size:
-                    # keep reading data
-                    read_chunk = next(it)
-                    buffered_chunk += read_chunk
-                    continue
-                else:
-                    write_chunk = buffered_chunk[:write_chunk_size]
-                    remained_data = buffered_chunk[write_chunk_size:]
-                    os_hash_value.update(write_chunk)
-                    checksum.update(write_chunk)
-                    if verifier:
-                        verifier.update(write_chunk)
-                    fp = io.BytesIO(write_chunk)
-                    fp.seek(0)
-                    part = UploadPart(mpu, fp, cstart + 1, len(write_chunk))
-                    pool.spawn_n(run_upload, s3_client, bucket, key, part)
-                    plist.append(part)
-                    cstart += 1
-                    buffered_chunk = remained_data
-            except StopIteration:
-                if len(buffered_chunk) > 0:
-                    # Write the last chunk data
-                    write_chunk = buffered_chunk
-                    os_hash_value.update(write_chunk)
-                    checksum.update(write_chunk)
-                    if verifier:
-                        verifier.update(write_chunk)
-                    fp = io.BytesIO(write_chunk)
-                    fp.seek(0)
-                    part = UploadPart(mpu, fp, cstart + 1, len(write_chunk))
-                    pool.spawn_n(run_upload, s3_client, bucket, key, part)
-                    plist.append(part)
-                break
-
-        pedict = {}
-        total_size = 0
-        pool.waitall()
-
-        for part in plist:
-            pedict.update(part.etag)
-            total_size += part.size
-
-        success = True
-        for part in plist:
-            if not part.success:
-                success = False
+        # Replace eventlet.GreenPool with ThreadPoolExecutor
+        with futures.ThreadPoolExecutor(
+                max_workers=pool_size) as executor:
+            # Create a list to store the futures
+            futures_list = []
+            mpu = s3_client.create_multipart_upload(Bucket=bucket, Key=key)
+            upload_id = mpu['UploadId']
+            LOG.debug("Multipart initiate key=%(key)s, UploadId=%(UploadId)s",
+                      {'key': key, 'UploadId': upload_id})
+            cstart = 0
+            plist = []
+
+            chunk_size = int(math.ceil(float(image_size) / MAX_PART_NUM))
+            write_chunk_size = max(self.s3_store_large_object_chunk_size,
+                                   chunk_size)
+            it = utils.chunkreadable(image_file, self.WRITE_CHUNKSIZE)
+            buffered_chunk = b''
+            total_bytes = 0
+            while True:
+                try:
+                    buffered_clen = len(buffered_chunk)
+                    if buffered_clen < write_chunk_size:
+                        # keep reading data
+                        read_chunk = next(it)
+                        buffered_chunk += read_chunk
+                        continue
+                    else:
+                        write_chunk = buffered_chunk[:write_chunk_size]
+                        remained_data = buffered_chunk[write_chunk_size:]
+                        total_bytes += len(write_chunk)
+                        if image_size != 0 and total_bytes > image_size:
+                            # Abort multipart upload immediately
+                            s3_client.abort_multipart_upload(
+                                Bucket=bucket, Key=key, UploadId=upload_id)
+                            raise glance_store.Invalid(
+                                _("Size exceeds: expected "
+                                  "%(expected)d "
+                                  "bytes, got %(actual)d bytes") %
+                                {'expected': image_size,
+                                 'actual': total_bytes})
+                        os_hash_value.update(write_chunk)
+                        checksum.update(write_chunk)
+                        if verifier:
+                            verifier.update(write_chunk)
+                        fp = io.BytesIO(write_chunk)
+                        fp.seek(0)
+                        part = UploadPart(
+                            mpu, fp, cstart + 1, len(write_chunk))
+                        # Spawn thread to upload part
+                        futures_list.append(executor.submit(
+                            run_upload, s3_client, bucket, key, part))
+                        plist.append(part)
+                        cstart += 1
+                        buffered_chunk = remained_data
+                except StopIteration:
+                    if len(buffered_chunk) > 0:
+                        # Write the last chunk data
+                        write_chunk = buffered_chunk
+                        total_bytes += len(write_chunk)
+                        os_hash_value.update(write_chunk)
+                        checksum.update(write_chunk)
+                        if verifier:
+                            verifier.update(write_chunk)
+                        fp = io.BytesIO(write_chunk)
+                        fp.seek(0)
+                        part = UploadPart(
+                            mpu, fp, cstart + 1, len(write_chunk))
+                        futures_list.append(executor.submit(
+                            run_upload, s3_client, bucket, key, part))
+                        plist.append(part)
+                    break
+
+        # Wait for all uploads to finish
+        futures.wait(futures_list)
+
+        # Final size validation after all parts uploaded
+        if image_size != 0 and total_bytes != image_size:
+            # Abort upload if mismatch (redundant check)
+            s3_client.abort_multipart_upload(
+                Bucket=bucket, Key=key, UploadId=upload_id)
+            raise glance_store.Invalid(
+                _("Size mismatch: expected %(expected)d "
+                  "bytes, got %(actual)d bytes") %
+                {'expected': image_size, 'actual': total_bytes})
+
+        # Check success status
+        success = all(p.success for p in plist)
+        total_size = sum(p.size for p in plist)
 
         if success:
             # Complete
+            pedict = {p.partnum: p.etag[p.partnum] for p in plist}
             mpu_list = self._get_mpu_list(pedict)
             s3_client.complete_multipart_upload(Bucket=bucket,
                                                 Key=key,
diff -pruN 4.9.1-2/glance_store/_drivers/swift/connection_manager.py 5.0.0-0ubuntu2/glance_store/_drivers/swift/connection_manager.py
--- 4.9.1-2/glance_store/_drivers/swift/connection_manager.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/swift/connection_manager.py	2025-07-10 09:13:16.000000000 +0000
@@ -78,8 +78,8 @@ class SwiftConnectionManager(object):
             # we are refreshing token only and if only connection manager
             # re-authentication is allowed. Token refreshing is setup by
             # connection manager users. Also we disable re-authentication
-            # if there is not way to execute it (cannot initialize trusts for
-            # multi-tenant or auth_version is not 3)
+            # if there is no way to execute it (cannot initialize trusts for
+            # multi-tenant)
             auth_ref = self.client.session.auth.auth_ref
             # if connection token is going to expire soon (keystone checks
             # is token is going to expire or expired already)
@@ -153,29 +153,18 @@ class SingleTenantConnectionManager(Swif
         if self.store.conf_endpoint:
             return self.store.conf_endpoint
 
-        if self.store.auth_version == '3':
-            try:
-                return self.client.session.get_endpoint(
-                    service_type=self.store.service_type,
-                    interface=self.store.endpoint_type,
-                    region_name=self.store.region
-                )
-            except Exception as e:
-                # do the same that swift driver does
-                # when catching ClientException
-                msg = _("Cannot find swift service endpoint : "
-                        "%s") % encodeutils.exception_to_unicode(e)
-                raise exceptions.BackendException(msg)
-
-    def _init_connection(self):
-        if self.store.auth_version == '3':
-            return super(SingleTenantConnectionManager,
-                         self)._init_connection()
-        else:
-            # no re-authentication for v1 and v2
-            self.allow_reauth = False
-            # use good old connection initialization
-            return self.store.get_connection(self.location, self.context)
+        try:
+            return self.client.session.get_endpoint(
+                service_type=self.store.service_type,
+                interface=self.store.endpoint_type,
+                region_name=self.store.region
+            )
+        except Exception as e:
+            # do the same that swift driver does
+            # when catching ClientException
+            msg = _("Cannot find swift service endpoint : "
+                    "%s") % encodeutils.exception_to_unicode(e)
+            raise exceptions.BackendException(msg)
 
 
 class MultiTenantConnectionManager(SwiftConnectionManager):
diff -pruN 4.9.1-2/glance_store/_drivers/swift/store.py 5.0.0-0ubuntu2/glance_store/_drivers/swift/store.py
--- 4.9.1-2/glance_store/_drivers/swift/store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/swift/store.py	2025-07-10 09:13:16.000000000 +0000
@@ -149,8 +149,6 @@ Endpoint Type of Swift service.
 This string value indicates the endpoint type to use to fetch the
 Swift endpoint. The endpoint type determines the actions the user will
 be allowed to perform, for instance, reading and writing to the Store.
-This setting is only used if swift_store_auth_version is greater than
-1.
 
 Possible values:
     * publicURL
@@ -170,11 +168,6 @@ Provide a string value representing the
 storing images while using Swift backend storage. The default
 service type is set to ``object-store``.
 
-NOTE: If ``swift_store_auth_version`` is set to 2, the value for
-this configuration option needs to be ``object-store``. If using
-a higher version of Keystone or a different auth scheme, this
-option may be modified.
-
 Possible values:
     * A string representing a valid service type for Swift storage.
 
@@ -977,14 +970,18 @@ class BaseStore(driver.Store):
                         if image_size == 0:
                             content_length = None
                         else:
-                            left = image_size - combined_chunks_size
-                            if left == 0:
-                                break
-                            if chunk_size > left:
-                                chunk_size = left
                             content_length = chunk_size
-
                         chunk_name = "%s-%05d" % (location.obj, chunk_id)
+                        # Check if actual data exceeds the specified
+                        # image_size
+                        if (image_size != 0 and
+                                combined_chunks_size > image_size):
+                            raise glance_store.Invalid(
+                                _("Size exceeds: expected "
+                                  "%(expected)d "
+                                  "bytes, got %(actual)d bytes") %
+                                {'expected': image_size,
+                                 'actual': combined_chunks_size})
 
                         with self.reader_class(
                                 image_file, checksum, os_hash_value,
@@ -1026,10 +1023,17 @@ class BaseStore(driver.Store):
 
                         chunk_id += 1
                         combined_chunks_size += bytes_read
-                    # In the case we have been given an unknown image size,
-                    # set the size to the total size of the combined chunks.
-                    if image_size == 0:
-                        image_size = combined_chunks_size
+
+                    # Validate total size after all chunks are uploaded
+                    if image_size != 0 and combined_chunks_size != image_size:
+                        message = (_("Size mismatch: expected %(expected)d "
+                                     "bytes, got %(actual)d bytes") %
+                                   {'expected': image_size,
+                                    'actual': combined_chunks_size})
+                        raise glance_store.Invalid(message=message)
+
+                    # Assign actual written data size
+                    image_size = combined_chunks_size
 
                     # Now we write the object manifest in X-Object-Manifest
                     # header as defined for Dynamic Large Objects (DLO) Mode.
@@ -1066,6 +1070,15 @@ class BaseStore(driver.Store):
                 return (location.get_uri(credentials_included=include_creds),
                         image_size, obj_etag, os_hash_value.hexdigest(),
                         metadata)
+            except exceptions.Invalid:
+                with excutils.save_and_reraise_exception():
+                    LOG.error(_("Error during chunked upload "
+                                "to backend, deleting stale "
+                                "chunks."))
+                    self._delete_stale_chunks(
+                        manager.get_connection(),
+                        location.container,
+                        written_chunks)
             except swiftclient.ClientException as e:
                 if e.http_status == http.client.CONFLICT:
                     msg = _("Swift already has an image at this location")
@@ -1394,17 +1407,13 @@ class SingleTenantStore(BaseStore):
         if not auth_url.endswith('/'):
             auth_url += '/'
 
-        if self.auth_version in ('2', '3'):
-            try:
-                tenant_name, user = location.user.split(':')
-            except ValueError:
-                reason = (_("Badly formed tenant:user '%(user)s' in "
-                            "Swift URI") % {'user': location.user})
-                LOG.info(reason)
-                raise exceptions.BadStoreUri(message=reason)
-        else:
-            tenant_name = None
-            user = location.user
+        try:
+            tenant_name, user = location.user.split(':')
+        except ValueError:
+            reason = (_("Badly formed tenant:user '%(user)s' in "
+                        "Swift URI") % {'user': location.user})
+            LOG.info(reason)
+            raise exceptions.BadStoreUri(message=reason)
 
         os_options = {}
         if self.region:
diff -pruN 4.9.1-2/glance_store/_drivers/swift/utils.py 5.0.0-0ubuntu2/glance_store/_drivers/swift/utils.py
--- 4.9.1-2/glance_store/_drivers/swift/utils.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/swift/utils.py	2025-07-10 09:13:16.000000000 +0000
@@ -14,6 +14,7 @@
 
 import configparser
 import logging
+import warnings
 
 from oslo_config import cfg
 
@@ -40,14 +41,14 @@ Related options:
     * None
 
 """),
-    cfg.StrOpt('swift_store_auth_version', default='2',
-               help='Version of the authentication service to use. '
-                    'Valid versions are 2 and 3 for keystone and 1 '
-                    '(deprecated) for swauth and rackspace.',
+    cfg.StrOpt('swift_store_auth_version', default='3',
+               choices=['3'],
+               help='The authentication version to be used. Currently '
+                    'The only valid version is 3.',
                deprecated_for_removal=True,
                deprecated_reason="""
-The option 'auth_version' in the Swift back-end configuration file is
-used instead.
+This option is kept for backword-compatibility reasons but is no longer
+required, because only the single version (3) is supported now.
 """),
     cfg.StrOpt('swift_store_auth_address',
                help='The address where the Swift authentication '
@@ -209,6 +210,11 @@ class SwiftParams(object):
 
                 try:
                     reference['auth_version'] = CONFIG.get(ref, 'auth_version')
+                    warnings.warn(
+                        'The auth_version option is deprecated. It is kept '
+                        'for backword-compatibility reasons but will be '
+                        'removed in a future release.',
+                        DeprecationWarning)
                 except configparser.NoOptionError:
                     if self.backend_group:
                         av = getattr(
@@ -218,6 +224,9 @@ class SwiftParams(object):
                         av = self.conf.glance_store.swift_store_auth_version
                     reference['auth_version'] = av
 
+                if reference['auth_version'] != '3':
+                    raise ValueError('Unsupported auth_version')
+
                 account_params[ref] = reference
             except (ValueError, SyntaxError, configparser.NoOptionError):
                 LOG.exception(_LE("Invalid format of swift store config cfg"))
diff -pruN 4.9.1-2/glance_store/_drivers/vmware_datastore.py 5.0.0-0ubuntu2/glance_store/_drivers/vmware_datastore.py
--- 4.9.1-2/glance_store/_drivers/vmware_datastore.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/_drivers/vmware_datastore.py	2025-07-10 09:13:16.000000000 +0000
@@ -363,6 +363,11 @@ class Store(glance_store.Store):
         LOG.warning("The VMWare Datastore has been deprecated because "
                     "the vmwareapi driver in nova was marked experimental and "
                     "may be removed in a future release.")
+        if self.backend_group:
+            self.store_conf = glance_store.driver.BackendGroupConfiguration(
+                self.OPTIONS, self.backend_group, conf=self.conf)
+        else:
+            self.store_conf = self.conf.glance_store
 
     def reset_session(self):
         self.session = api.VMwareAPISession(
@@ -376,18 +381,13 @@ class Store(glance_store.Store):
         return (STORE_SCHEME,)
 
     def _sanity_check(self):
-        if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
-        else:
-            store_conf = self.conf.glance_store
-
-        if store_conf.vmware_api_retry_count <= 0:
+        if self.store_conf.vmware_api_retry_count <= 0:
             msg = _('vmware_api_retry_count should be greater than zero')
             LOG.error(msg)
             raise exceptions.BadStoreConfiguration(
                 store_name='vmware_datastore', reason=msg)
 
-        if store_conf.vmware_task_poll_interval <= 0:
+        if self.store_conf.vmware_task_poll_interval <= 0:
             msg = _('vmware_task_poll_interval should be greater than zero')
             LOG.error(msg)
             raise exceptions.BadStoreConfiguration(
@@ -400,15 +400,10 @@ class Store(glance_store.Store):
         self.server_username = self._option_get('vmware_server_username')
         self.server_password = self._option_get('vmware_server_password')
 
-        if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
-        else:
-            store_conf = self.conf.glance_store
-
-        self.api_retry_count = store_conf.vmware_api_retry_count
-        self.tpoll_interval = store_conf.vmware_task_poll_interval
-        self.ca_file = store_conf.vmware_ca_file
-        self.api_insecure = store_conf.vmware_insecure
+        self.api_retry_count = self.store_conf.vmware_api_retry_count
+        self.tpoll_interval = self.store_conf.vmware_task_poll_interval
+        self.ca_file = self.store_conf.vmware_ca_file
+        self.api_insecure = self.store_conf.vmware_insecure
         if api is None:
             msg = _("Missing dependencies: oslo_vmware")
             raise exceptions.BadStoreConfiguration(
@@ -506,12 +501,7 @@ class Store(glance_store.Store):
         datastores = self._option_get('vmware_datastores')
         self.datastores = self._build_datastore_weighted_map(datastores)
 
-        if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
-        else:
-            store_conf = self.conf.glance_store
-
-        self.store_image_dir = store_conf.vmware_store_image_dir
+        self.store_image_dir = self.store_conf.vmware_store_image_dir
         if self.backend_group:
             self._set_url_prefix()
 
@@ -545,12 +535,7 @@ class Store(glance_store.Store):
         raise exceptions.StorageFull()
 
     def _option_get(self, param):
-        if self.backend_group:
-            store_conf = getattr(self.conf, self.backend_group)
-        else:
-            store_conf = self.conf.glance_store
-
-        result = getattr(store_conf, param)
+        result = getattr(self.store_conf, param)
         if result is None:
             reason = (_("Could not find %(param)s in configuration "
                         "options.") % {'param': param})
diff -pruN 4.9.1-2/glance_store/driver.py 5.0.0-0ubuntu2/glance_store/driver.py
--- 4.9.1-2/glance_store/driver.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/driver.py	2025-07-10 09:13:16.000000000 +0000
@@ -31,6 +31,8 @@ from glance_store.i18n import _
 
 LOG = logging.getLogger(__name__)
 
+CONF = cfg.CONF
+SHARED_CONF_GROUP = 'backend_defaults'
 
 _MULTI_BACKEND_OPTS = [
     cfg.StrOpt('store_description',
@@ -80,6 +82,7 @@ class Store(capabilities.StoreCapability
                             self.MULTI_BACKEND_OPTIONS, group=group)
 
                 self.conf.register_opts(self.OPTIONS, group=group)
+                self.conf.register_opts(self.OPTIONS, group=SHARED_CONF_GROUP)
         except cfg.DuplicateOptError:
             pass
 
@@ -300,3 +303,62 @@ def back_compat_add(store_add_fun):
                 metadata_dict)
 
     return add_adapter
+
+
+class BackendGroupConfiguration(object):
+
+    def __init__(self, store_opts, config_group=None, conf=None):
+        """Initialize configuration.
+
+        This takes care of grafting the implementation's config
+        values into the config group and shared defaults. We will try to
+        pull values from the specified 'config_group', but fall back to
+        defaults from the SHARED_CONF_GROUP.
+        """
+        self.config_group = config_group
+        self.conf = conf or CONF
+
+        # set the local conf so that __call__'s know what to use
+        self._ensure_config_values(store_opts)
+        self.backend_conf = self.conf._get(self.config_group)
+        self.shared_backend_conf = self.conf._get(SHARED_CONF_GROUP)
+
+    def _safe_register(self, opt, group):
+        try:
+            CONF.register_opt(opt, group=group)
+        except cfg.DuplicateOptError:
+            pass  # If it's already registered ignore it
+
+    def _ensure_config_values(self, store_opts):
+        """Register the options in the shared group.
+
+        When we go to get a config option we will try the backend specific
+        group first and fall back to the shared group. We override the default
+        from all the config options for the backend group so we can know if it
+        was set or not.
+        """
+        for opt in store_opts:
+            self._safe_register(opt, SHARED_CONF_GROUP)
+            # Assuming they aren't the same groups, graft on the options into
+            # the backend group and override its default value.
+            if self.config_group != SHARED_CONF_GROUP:
+                self._safe_register(opt, self.config_group)
+                self.conf.set_default(opt.name, None, group=self.config_group)
+
+    def append_config_values(self, store_opts):
+        self._ensure_config_values(store_opts)
+
+    def set_default(self, opt_name, default):
+        self.conf.set_default(opt_name, default, group=SHARED_CONF_GROUP)
+
+    def get(self, key, default=None):
+        return getattr(self, key, default)
+
+    def __getattr__(self, opt_name):
+        # Don't use self.X to avoid reentrant call to __getattr__()
+        backend_conf = object.__getattribute__(self, 'backend_conf')
+        opt_value = getattr(backend_conf, opt_name)
+        if opt_value is None:
+            shared_conf = object.__getattribute__(self, 'shared_backend_conf')
+            opt_value = getattr(shared_conf, opt_name)
+        return opt_value
diff -pruN 4.9.1-2/glance_store/tests/functional/base.py 5.0.0-0ubuntu2/glance_store/tests/functional/base.py
--- 4.9.1-2/glance_store/tests/functional/base.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/functional/base.py	2025-07-10 09:13:16.000000000 +0000
@@ -17,7 +17,7 @@ import io
 from os import environ
 
 import glance_store
-import os_client_config
+from openstack import config as occ
 from oslo_config import cfg
 import testtools
 
@@ -39,8 +39,7 @@ class Base(testtools.TestCase):
         # check whether a particular cloud should be used
         cloud = environ.get('OS_TEST_GLANCE_STORE_FUNC_TEST_CLOUD',
                             'devstack-admin')
-        creds = os_client_config.OpenStackConfig().get_one_cloud(
-            cloud=cloud)
+        creds = occ.OpenStackConfig().get_one(cloud=cloud)
         auth = creds.get_auth_args()
         self.username = auth["username"]
         self.password = auth["password"]
diff -pruN 4.9.1-2/glance_store/tests/unit/cinder/test_cinder_base.py 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_cinder_base.py
--- 4.9.1-2/glance_store/tests/unit/cinder/test_cinder_base.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_cinder_base.py	2025-07-10 09:13:16.000000000 +0000
@@ -577,6 +577,55 @@ class TestCinderStoreBase(object):
             if is_multi_store:
                 self.assertEqual(backend, metadata["store"])
 
+    def _test_cinder_add_size_validation(
+            self, fake_volume, volume_file, verifier=None, size_kb=5,
+            backend='glance_store', is_multi_store=False, oversized=False):
+        expected_image_id = str(uuid.uuid4())
+        expected_size = size_kb * units.Ki
+        if oversized:
+            # 1 KB over
+            self.store.WRITE_CHUNKSIZE = 1024
+            expected_file_contents = b"*" * (expected_size + 1024)
+            image_file = io.BytesIO(expected_file_contents)
+            expected_error = "Size exceeds: expected"
+        else:
+            # 1 KB less
+            expected_file_contents = b"*" * (expected_size - 1024)
+            image_file = io.BytesIO(expected_file_contents)
+            expected_error = "Size mismatch: expected"
+
+        if is_multi_store:
+            # Default backend is 'glance_store' for single store but in case
+            # of multi store, if the backend option is not passed, we should
+            # assign it to the default i.e. 'cinder1'
+            if backend == 'glance_store':
+                backend = 'cinder1'
+        self.config(cinder_volume_type='some_type', group=backend)
+
+        fake_client = mock.MagicMock(auth_token=None, management_url=None)
+        fake_volume.manager.get.return_value = fake_volume
+        fake_volumes = mock.MagicMock(create=mock.Mock(
+            return_value=fake_volume))
+
+        @contextlib.contextmanager
+        def fake_open(client, volume, mode):
+            self.assertEqual('wb', mode)
+            yield volume_file
+
+        with mock.patch.object(cinder.Store, 'get_cinderclient') as mock_cc, \
+                mock.patch.object(self.store, '_open_cinder_volume',
+                                  side_effect=fake_open):
+            mock_cc.return_value = mock.MagicMock(client=fake_client,
+                                                  volumes=fake_volumes)
+            self.assertRaisesRegex(
+                exceptions.Invalid, expected_error,
+                self.store.add, expected_image_id, image_file,
+                expected_size, self.hash_algo, self.context, verifier)
+
+            fake_volume.delete.assert_called_once()
+            self.assertEqual(image_file.tell(),
+                             len(expected_file_contents))
+
     def test_cinder_add_volume_not_found(self):
         image_file = mock.MagicMock()
         fake_image_id = str(uuid.uuid4())
diff -pruN 4.9.1-2/glance_store/tests/unit/cinder/test_cinder_store.py 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_cinder_store.py
--- 4.9.1-2/glance_store/tests/unit/cinder/test_cinder_store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_cinder_store.py	2025-07-10 09:13:16.000000000 +0000
@@ -114,6 +114,21 @@ class TestCinderStore(base.StoreBaseTest
         volume_file = io.BytesIO()
         self._test_cinder_add(fake_volume, volume_file)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
+                                     status='available',
+                                     size=1)
+        volume_file = io.BytesIO()
+        self._test_cinder_add_size_validation(fake_volume, volume_file,
+                                              oversized=True)
+
+    def test_write_less_than_declared_raises_exception(self):
+        fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
+                                     status='available',
+                                     size=1)
+        volume_file = io.BytesIO()
+        self._test_cinder_add_size_validation(fake_volume, volume_file)
+
     def test_cinder_add_with_verifier(self):
         fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
                                      status='available',
diff -pruN 4.9.1-2/glance_store/tests/unit/cinder/test_multistore_cinder.py 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_multistore_cinder.py
--- 4.9.1-2/glance_store/tests/unit/cinder/test_multistore_cinder.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/cinder/test_multistore_cinder.py	2025-07-10 09:13:16.000000000 +0000
@@ -253,6 +253,23 @@ class TestMultiCinderStore(base.MultiSto
         volume_file = io.BytesIO()
         self._test_cinder_add(fake_volume, volume_file, is_multi_store=True)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
+                                     status='available',
+                                     size=1)
+        volume_file = io.BytesIO()
+        self._test_cinder_add_size_validation(fake_volume, volume_file,
+                                              oversized=True,
+                                              is_multi_store=True)
+
+    def test_write_less_than_declared_raises_exception(self):
+        fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
+                                     status='available',
+                                     size=1)
+        volume_file = io.BytesIO()
+        self._test_cinder_add_size_validation(fake_volume, volume_file,
+                                              is_multi_store=True)
+
     def test_cinder_add_with_verifier(self):
         fake_volume = mock.MagicMock(id=str(uuid.uuid4()),
                                      status='available',
diff -pruN 4.9.1-2/glance_store/tests/unit/test_backend_group_configuration.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_backend_group_configuration.py
--- 4.9.1-2/glance_store/tests/unit/test_backend_group_configuration.py	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_backend_group_configuration.py	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,77 @@
+# Copyright (c) 2025 RedHat Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+"""Tests for the configuration wrapper in Glance Store drivers."""
+
+from oslo_config import cfg
+from oslotest import base
+
+import glance_store.driver as driver
+
+store_opts = [
+    cfg.StrOpt('str_opt', default='STR_OPT'),
+    cfg.BoolOpt('bool_opt', default=False)
+]
+more_store_opts = [
+    cfg.IntOpt('int_opt', default=1),
+]
+
+CONF = cfg.CONF
+CONF.register_opts(store_opts)
+CONF.register_opts(more_store_opts)
+
+
+class BackendGroupConfigurationTest(base.BaseTestCase):
+
+    def override_config(self, name, override, group=None):
+        """Cleanly override CONF variables."""
+        CONF.set_override(name, override, group)
+        self.addCleanup(CONF.clear_override, name, group)
+
+    def test_group_grafts_opts(self):
+        c = driver.BackendGroupConfiguration(store_opts, config_group='foo')
+        self.assertEqual(c.str_opt, 'STR_OPT')
+        self.assertEqual(c.bool_opt, False)
+        self.assertEqual(c.str_opt, CONF.backend_defaults.str_opt)
+        self.assertEqual(c.bool_opt, CONF.backend_defaults.bool_opt)
+        self.assertIsNone(CONF.foo.str_opt)
+        self.assertIsNone(CONF.foo.bool_opt)
+
+    def test_grafting_multiple_opts(self):
+        c = driver.BackendGroupConfiguration(store_opts, config_group='foo')
+        c.append_config_values(more_store_opts)
+        self.assertEqual(c.str_opt, 'STR_OPT')
+        self.assertEqual(c.bool_opt, False)
+        self.assertEqual(c.int_opt, 1)
+
+        # We get the right values, but they are coming from the
+        # backend_defaults group of CONF and not the 'foo' one.
+        self.assertEqual(c.str_opt, CONF.backend_defaults.str_opt)
+        self.assertEqual(c.bool_opt, CONF.backend_defaults.bool_opt)
+        self.assertEqual(c.int_opt, CONF.backend_defaults.int_opt)
+        self.assertIsNone(CONF.foo.str_opt)
+        self.assertIsNone(CONF.foo.bool_opt)
+        self.assertIsNone(CONF.foo.int_opt)
+
+    def test_backend_specific_value(self):
+        c = driver.BackendGroupConfiguration(store_opts, config_group='foo')
+
+        self.override_config('str_opt', 'bar', group='backend_defaults')
+        actual_value = c.str_opt
+        self.assertEqual('bar', actual_value)
+
+        self.override_config('str_opt', 'notbar', group='foo')
+        actual_value = c.str_opt
+        self.assertEqual('notbar', actual_value)
diff -pruN 4.9.1-2/glance_store/tests/unit/test_connection_manager.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_connection_manager.py
--- 4.9.1-2/glance_store/tests/unit/test_connection_manager.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_connection_manager.py	2025-07-10 09:13:16.000000000 +0000
@@ -42,8 +42,7 @@ class TestConnectionManager(base.StoreBa
                                          service_type="swift",
                                          endpoint_type="internal",
                                          region=None,
-                                         conf=self.conf,
-                                         auth_version='3')
+                                         conf=self.conf)
 
         store.backend_group = None
         store.conf_endpoint = None
diff -pruN 4.9.1-2/glance_store/tests/unit/test_filesystem_store.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_filesystem_store.py
--- 4.9.1-2/glance_store/tests/unit/test_filesystem_store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_filesystem_store.py	2025-07-10 09:13:16.000000000 +0000
@@ -141,6 +141,54 @@ class TestStore(base.StoreBaseTest,
                           self.store.get,
                           loc)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        # Setup
+        expected_image_id = str(uuid.uuid4())
+        path = os.path.join(self.test_dir, expected_image_id)
+        # expected total size
+        expected_file_size = 1020
+        # simulate input with extra data
+        image_file = io.BytesIO(b'a' * (expected_file_size + 100))
+
+        # Call method and assert exception
+        self.assertRaisesRegex(
+            exceptions.Invalid, "Size exceeds: expected",
+            self.store.add, expected_image_id, image_file,
+            expected_file_size, self.hash_algo)
+
+        # Verify partial data is deleted from backend
+        self.assertFalse(os.path.exists(path))
+
+        # Verify that the stream's position reflects the number of bytes read,
+        # which should be exactly at expected_file_size plus the last buffer
+        # size read.
+        expected_read = expected_file_size + self.store.WRITE_CHUNKSIZE
+        self.assertEqual(expected_read, image_file.tell(),
+                         "The stream was not read only up to the expected "
+                         "size.")
+
+    def test_write_less_than_declared_raises_exception(self):
+        # Setup
+        expected_image_id = str(uuid.uuid4())
+        path = os.path.join(self.test_dir, expected_image_id)
+        # expected total size
+        actual_data_size = 800
+        # declared size larger than actual data
+        declared_size = 1000
+        image_file = io.BytesIO(b'b' * actual_data_size)
+
+        # Call method and assert exception
+        self.assertRaisesRegex(
+            exceptions.Invalid, "Size mismatch: expected",
+            self.store.add, expected_image_id, image_file,
+            declared_size, self.hash_algo)
+
+        # Verify partial data is deleted from backend
+        self.assertFalse(os.path.exists(path))
+        # The input buffer should be fully read
+        self.assertEqual(actual_data_size, image_file.tell(),
+                         "Input stream was not fully read as expected")
+
     def _do_test_add(self, enable_thin_provisoning):
         """Test that we can add an image via the filesystem backend."""
         self.config(filesystem_store_chunk_size=units.Ki,
diff -pruN 4.9.1-2/glance_store/tests/unit/test_multistore_filesystem.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_filesystem.py
--- 4.9.1-2/glance_store/tests/unit/test_multistore_filesystem.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_filesystem.py	2025-07-10 09:13:16.000000000 +0000
@@ -257,6 +257,52 @@ class TestMultiStore(base.MultiStoreBase
         self.assertEqual(expected_file_contents, new_image_contents)
         self.assertEqual(expected_file_size, new_image_file_size)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        # Setup
+        expected_image_id = str(uuid.uuid4())
+        path = os.path.join(self.test_dir, expected_image_id)
+        # expected total size
+        expected_file_size = 1020
+        # simulate input with extra data
+        image_file = io.BytesIO(b'a' * (expected_file_size + 100))
+
+        # Call method and assert exception
+        self.assertRaisesRegex(exceptions.Invalid, "Size exceeds: expected",
+                               self.store.add, expected_image_id, image_file,
+                               expected_file_size)
+
+        # Verify partial data is deleted from backend
+        self.assertFalse(os.path.exists(path))
+
+        # Verify that the stream's position reflects the number of bytes read,
+        # which should be exactly at expected_file_size plus the last buffer
+        # size read.
+        expected_read = expected_file_size + self.store.WRITE_CHUNKSIZE
+        self.assertEqual(expected_read, image_file.tell(),
+                         "The stream was not read only up to the expected "
+                         "size.")
+
+    def test_write_less_than_declared_raises_exception(self):
+        # Setup
+        expected_image_id = str(uuid.uuid4())
+        path = os.path.join(self.test_dir, expected_image_id)
+        # expected total size
+        actual_data_size = 800
+        # declared size larger than actual data
+        declared_size = 1000
+        image_file = io.BytesIO(b'b' * actual_data_size)
+
+        # Call method and assert exception
+        self.assertRaisesRegex(exceptions.Invalid, "Size mismatch: expected",
+                               self.store.add, expected_image_id, image_file,
+                               declared_size)
+
+        # Verify partial data is deleted from backend
+        self.assertFalse(os.path.exists(path))
+        # The input buffer should be fully read
+        self.assertEqual(actual_data_size, image_file.tell(),
+                         "Input stream was not fully read as expected")
+
     def test_add_check_metadata_with_invalid_mountpoint_location(self):
         in_metadata = [{'id': 'abcdefg',
                        'mountpoint': '/xyz/images'}]
@@ -450,6 +496,9 @@ class TestMultiStore(base.MultiStoreBase
         self.conf.set_override('filesystem_store_datadir',
                                override=None,
                                group='file1')
+        self.conf.set_override('filesystem_store_datadir',
+                               override=None,
+                               group='backend_defaults')
         self.conf.set_override('filesystem_store_datadirs',
                                [store_map[0] + ":100",
                                 store_map[1] + ":200"],
@@ -568,6 +617,9 @@ class TestMultiStore(base.MultiStoreBase
         self.conf.set_override('filesystem_store_datadir',
                                override=None,
                                group='file1')
+        self.conf.set_override('filesystem_store_datadir',
+                               override=None,
+                               group='backend_defaults')
         self.conf.set_override('filesystem_store_datadirs',
                                [store_map[0] + ":100",
                                 store_map[1] + ":200",
@@ -618,6 +670,9 @@ class TestMultiStore(base.MultiStoreBase
         self.conf.set_override('filesystem_store_datadir',
                                override=None,
                                group='file1')
+        self.conf.set_override('filesystem_store_datadir',
+                               override=None,
+                               group='backend_defaults')
 
         self.conf.set_override('filesystem_store_datadirs',
                                [store_map[0] + ":100",
@@ -670,6 +725,9 @@ class TestMultiStore(base.MultiStoreBase
         self.conf.set_override('filesystem_store_datadir',
                                override=None,
                                group='file1')
+        self.conf.set_override('filesystem_store_datadir',
+                               override=None,
+                               group='backend_defaults')
         self.conf.set_override('filesystem_store_datadirs',
                                [store_map[0] + ":100",
                                 store_map[1] + ":200"],
diff -pruN 4.9.1-2/glance_store/tests/unit/test_multistore_rbd.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_rbd.py
--- 4.9.1-2/glance_store/tests/unit/test_multistore_rbd.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_rbd.py	2025-07-10 09:13:16.000000000 +0000
@@ -84,6 +84,9 @@ class MockRBD(object):
     class ImageHasSnapshots(Exception):
         pass
 
+    class IncompleteWriteError(Exception):
+        pass
+
     class ImageBusy(Exception):
         pass
 
@@ -243,6 +246,47 @@ class TestMultiStore(base.MultiStoreBase
                 self.assertEqual(ret[1], self.data_len)
                 self.assertEqual("ceph1", ret[3]['store'])
 
+    @mock.patch.object(rbd_store.Store, '_delete_image')
+    def test_add_image_exceeding_max_size_raises_exception(self, mock_delete):
+        self.store.chunk_size = units.Ki
+        self.store.WRITE_CHUNKSIZE = 1024
+        total_bytes = units.Ki * 5
+        # actual data size
+        image_size = total_bytes
+        # Create data larger than image_size to simulate mismatch at end
+        data = b'a' * (total_bytes + 1024)
+        image_file = io.BytesIO(data)
+        with mock.patch.object(rbd_store.rbd.Image, 'write'):
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, 'fake_image_id', image_file,
+                image_size)
+
+            # Confirm that image deletion was called due to size mismatch
+            mock_delete.assert_called()
+            # The position should be equal to total input size
+            self.assertEqual(image_file.tell(), len(data))
+
+    @mock.patch.object(rbd_store.Store, '_delete_image')
+    def test_write_less_than_declared_raises_exception(self, mock_delete):
+        self.store.chunk_size = units.Ki
+        total_bytes = units.Ki * 5
+        # actual data size
+        image_size = total_bytes
+        # Create data larger than image_size to simulate mismatch at end
+        data = b'a' * (total_bytes - 100)
+        image_file = io.BytesIO(data)
+        with mock.patch.object(rbd_store.rbd.Image, 'write'):
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size mismatch: expected",
+                self.store.add, 'fake_image_id', image_file,
+                image_size)
+
+            # Confirm that image deletion was called due to size mismatch
+            mock_delete.assert_called()
+            # The position should be less than total input size
+            self.assertLessEqual(image_file.tell(), len(data))
+
     def test_add_w_image_size_zero_to_different_backend(self):
         """Assert that correct size is returned even though 0 was provided."""
         self.store = rbd_store.Store(self.conf, backend="ceph2")
diff -pruN 4.9.1-2/glance_store/tests/unit/test_multistore_s3.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_s3.py
--- 4.9.1-2/glance_store/tests/unit/test_multistore_s3.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_multistore_s3.py	2025-07-10 09:13:16.000000000 +0000
@@ -292,6 +292,119 @@ class TestMultiS3Store(base.MultiStoreBa
             self.assertEqual(expected_multihash, multihash)
 
     @mock.patch.object(boto3.session.Session, "client")
+    def test_add_singlepart_size_exceeding_max_size(self, mock_client):
+        """Test size validation during add for singlepart upload."""
+        self.store.WRITE_CHUNKSIZE = 1024
+        expected_image_id = str(uuid.uuid4())
+        # Provide a smaller expected size than actual data to trigger
+        # size mismatch
+        expected_s3_size = FIVE_KB
+        # 5KB more than expected
+        actual_s3_contents = b"*" * (expected_s3_size * 2)
+        image_s3 = io.BytesIO(actual_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='put_object',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'Body': botocore.stub.ANY
+                                 })
+
+            mock_client.return_value = fake_s3_client
+
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(exceptions.Invalid,
+                                   'Size exceeds: expected',
+                                   self.store.add,
+                                   expected_image_id, image_s3,
+                                   expected_s3_size, self.hash_algo)
+
+            # Verify that the stream's position reflects the number of bytes
+            # read, which should be exactly at expected_file_size plus the
+            # last buffer size read.
+            actual_read_size = image_s3.tell()
+            expected_read = expected_s3_size + self.store.WRITE_CHUNKSIZE
+            self.assertEqual(actual_read_size, expected_read,
+                             "The stream was not read only up to the expected "
+                             "size.")
+
+    @mock.patch.object(boto3.session.Session, "client")
+    def test_add_singlepart_write_less_than_declared(self, mock_client):
+        """Test size validation during add for singlepart upload."""
+        expected_image_id = str(uuid.uuid4())
+        # Provide a smaller expected size than actual data to trigger
+        # size mismatch
+        expected_s3_size = FIVE_KB
+        # 100 bytes smaller than expected
+        actual_s3_contents = b"*" * (FIVE_KB - 100)
+        image_s3 = io.BytesIO(actual_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            # Add a second head_object call to match the code's behavior
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='put_object',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'Body': botocore.stub.ANY
+                                 })
+
+            mock_client.return_value = fake_s3_client
+
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(exceptions.Invalid,
+                                   'Size mismatch: expected',
+                                   self.store.add,
+                                   expected_image_id, image_s3,
+                                   expected_s3_size, self.hash_algo)
+            # The input buffer should be fully read
+            # depending on implementation
+            total_input_size = len(actual_s3_contents)
+            self.assertEqual(image_s3.tell(), total_input_size)
+
+    @mock.patch.object(boto3.session.Session, "client")
     def test_add_singlepart_bigger_than_write_chunk(self, mock_client):
         """Test that we can add an image via the s3 backend."""
         expected_image_id = str(uuid.uuid4())
@@ -514,6 +627,137 @@ class TestMultiS3Store(base.MultiStoreBa
             self.assertEqual(expected_multihash, multihash)
 
     @mock.patch.object(boto3.session.Session, "client")
+    def test_add_multipart_size_exceeding_max_size(self, mock_client):
+        """Test size validation during multipart upload."""
+        expected_image_id = str(uuid.uuid4())
+        expected_s3_size = 15 * units.Mi
+        self.store.WRITE_CHUNKSIZE = 5 * units.Mi
+        # Actual data is larger than expected to trigger size validation
+        # failure, 5MB larger
+        total_size = expected_s3_size + self.store.WRITE_CHUNKSIZE
+        expected_s3_contents = b"*" * total_size
+        image_s3 = io.BytesIO(expected_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+        # Patch abort_multipart_upload on the client to a Mock
+        fake_s3_client.abort_multipart_upload = mock.Mock()
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='create_multipart_upload',
+                                 service_response={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                     "UploadId": 'UploadId'
+                                 },
+                                 expected_params={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                 })
+            stubber.add_response(method='abort_multipart_upload',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'UploadId': 'UploadId'
+                                 })
+
+            mock_client.return_value = fake_s3_client
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, expected_image_id, image_s3,
+                expected_s3_size, self.hash_algo)
+
+            # Verify that the stream's position reflects the number of bytes
+            # read, which should be exactly at expected_file_size plus the
+            # last buffer size read.
+            actual_read_size = image_s3.tell()
+            self.assertEqual(actual_read_size, total_size,
+                             "The stream was not read only up to the expected "
+                             "size.")
+
+            # Assert that abort_multipart_upload was called
+            fake_s3_client.abort_multipart_upload.assert_called_once_with(
+                Bucket=S3_CONF['s3_store_bucket'],
+                Key=expected_image_id,
+                UploadId='UploadId'
+            )
+
+    @mock.patch.object(boto3.session.Session, "client")
+    def test_add_multipart_write_less_than_declared(self, mock_client):
+        """Test size validation during multipart upload."""
+        expected_image_id = str(uuid.uuid4())
+        expected_s3_size = 16 * units.Mi
+        # Actual data is less than expected to trigger size validation
+        # failure, 1MB less
+        expected_s3_contents = b"*" * (expected_s3_size - 1 * units.Mi)
+        image_s3 = io.BytesIO(expected_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+        # Patch abort_multipart_upload on the client to a Mock
+        fake_s3_client.abort_multipart_upload = mock.Mock()
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='create_multipart_upload',
+                                 service_response={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                     "UploadId": 'UploadId'
+                                 },
+                                 expected_params={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                 })
+            stubber.add_response(method='abort_multipart_upload',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'UploadId': 'UploadId'
+                                 })
+
+            mock_client.return_value = fake_s3_client
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(exceptions.Invalid,
+                                   'Size mismatch: expected',
+                                   self.store.add,
+                                   expected_image_id, image_s3,
+                                   expected_s3_size, self.hash_algo)
+
+            # The input buffer should be fully read depending on implementation
+            total_input_size = len(expected_s3_contents)
+            self.assertEqual(image_s3.tell(), total_input_size)
+
+            # Assert that abort_multipart_upload was called
+            fake_s3_client.abort_multipart_upload.assert_called_once_with(
+                Bucket=S3_CONF['s3_store_bucket'],
+                Key=expected_image_id,
+                UploadId='UploadId'
+            )
+
+    @mock.patch.object(boto3.session.Session, "client")
     def test_add_already_existing(self, mock_client):
         """Tests that adding an image with an existing identifier raises an
         appropriate exception
diff -pruN 4.9.1-2/glance_store/tests/unit/test_rbd_store.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_rbd_store.py
--- 4.9.1-2/glance_store/tests/unit/test_rbd_store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_rbd_store.py	2025-07-10 09:13:16.000000000 +0000
@@ -84,6 +84,9 @@ class MockRBD(object):
     class ImageHasSnapshots(Exception):
         pass
 
+    class IncompleteWriteError(Exception):
+        pass
+
     class ImageBusy(Exception):
         pass
 
@@ -343,6 +346,47 @@ class TestStore(base.StoreBaseTest,
                 self.assertTrue(write.called)
                 self.assertEqual(ret[1], self.data_len)
 
+    @mock.patch.object(rbd_store.Store, '_delete_image')
+    def test_add_image_exceeding_max_size_raises_exception(self, mock_delete):
+        self.store.chunk_size = units.Ki
+        self.store.WRITE_CHUNKSIZE = 1024
+        total_bytes = units.Ki * 5
+        # actual data size
+        image_size = total_bytes
+        # Create data larger than image_size to simulate mismatch at end
+        data = b'a' * (total_bytes + 1024)
+        image_file = io.BytesIO(data)
+        with mock.patch.object(rbd_store.rbd.Image, 'write'):
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, 'fake_image_id', image_file,
+                image_size, self.hash_algo)
+
+            # Confirm that image deletion was called due to size mismatch
+            mock_delete.assert_called()
+            # The position should be equal to total input size
+            self.assertEqual(image_file.tell(), len(data))
+
+    @mock.patch.object(rbd_store.Store, '_delete_image')
+    def test_write_less_than_declared_raises_exception(self, mock_delete):
+        self.store.chunk_size = units.Ki
+        total_bytes = units.Ki * 5
+        # actual data size
+        image_size = total_bytes
+        # Create data larger than image_size to simulate mismatch at end
+        data = b'a' * (total_bytes - 100)
+        image_file = io.BytesIO(data)
+        with mock.patch.object(rbd_store.rbd.Image, 'write'):
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size mismatch: expected",
+                self.store.add, 'fake_image_id', image_file,
+                image_size, self.hash_algo)
+
+            # Confirm that image deletion was called due to size mismatch
+            mock_delete.assert_called()
+            # The position should be less than total input size
+            self.assertEqual(image_file.tell(), len(data))
+
     @mock.patch.object(MockRBD.Image, '__enter__')
     @mock.patch.object(rbd_store.Store, '_create_image')
     @mock.patch.object(rbd_store.Store, '_delete_image')
diff -pruN 4.9.1-2/glance_store/tests/unit/test_s3_store.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_s3_store.py
--- 4.9.1-2/glance_store/tests/unit/test_s3_store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_s3_store.py	2025-07-10 09:13:16.000000000 +0000
@@ -253,6 +253,106 @@ class TestStore(base.StoreBaseTest,
             self.assertEqual(expected_multihash, multihash)
 
     @mock.patch.object(boto3.session.Session, "client")
+    def test_add_singlepart_size_exceeding_max_size(self, mock_client):
+        """Test size validation during add for singlepart upload."""
+        self.store.WRITE_CHUNKSIZE = 1024
+        expected_image_id = str(uuid.uuid4())
+        # Provide a smaller expected size than actual data to trigger
+        # size mismatch
+        expected_s3_size = FIVE_KB
+        # 5KB more than expected
+        actual_s3_contents = b"*" * (expected_s3_size * 2)
+        image_s3 = io.BytesIO(actual_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='put_object',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'Body': botocore.stub.ANY
+                                 })
+
+            mock_client.return_value = fake_s3_client
+
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(exceptions.Invalid,
+                                   'Size exceeds: expected',
+                                   self.store.add,
+                                   expected_image_id, image_s3,
+                                   expected_s3_size, self.hash_algo)
+            # Verify that the stream's position reflects the number of bytes
+            # read, which should be exactly at expected_file_size plus the
+            # last buffer size read.
+            actual_read_size = image_s3.tell()
+            expected_read = expected_s3_size + self.store.WRITE_CHUNKSIZE
+            self.assertEqual(actual_read_size, expected_read,
+                             "The stream was not read only up to the expected "
+                             "size.")
+
+    @mock.patch.object(boto3.session.Session, "client")
+    def test_add_singlepart_write_less_than_declared(self, mock_client):
+        """Test size validation during add for singlepart upload."""
+        expected_image_id = str(uuid.uuid4())
+        # Provide a smaller expected size than actual data to trigger
+        # size mismatch
+        expected_s3_size = FIVE_KB
+        # 100 bytes smaller than expected
+        actual_s3_contents = b"*" * (FIVE_KB - 100)
+        image_s3 = io.BytesIO(actual_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='put_object',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'Body': botocore.stub.ANY
+                                 })
+
+            mock_client.return_value = fake_s3_client
+
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(exceptions.Invalid,
+                                   'Size mismatch: expected',
+                                   self.store.add,
+                                   expected_image_id, image_s3,
+                                   expected_s3_size, self.hash_algo)
+
+            # The input buffer should be fully read
+            # depending on implementation
+            total_input_size = len(actual_s3_contents)
+            self.assertEqual(image_s3.tell(), total_input_size)
+
+    @mock.patch.object(boto3.session.Session, "client")
     def test_add_singlepart_bigger_than_write_chunk(self, mock_client):
         """Test that we can add a large image via the s3 backend."""
         expected_image_id = str(uuid.uuid4())
@@ -419,6 +519,136 @@ class TestStore(base.StoreBaseTest,
             self.assertEqual(expected_multihash, multihash)
 
     @mock.patch.object(boto3.session.Session, "client")
+    def test_add_multipart_size_exceeding_max_size(self, mock_client):
+        """Test size validation during multipart upload."""
+        expected_image_id = str(uuid.uuid4())
+        expected_s3_size = 15 * units.Mi
+        self.store.WRITE_CHUNKSIZE = 5 * units.Mi
+        # Actual data is larger than expected to trigger size validation
+        # failure, 5MB larger
+        total_size = expected_s3_size + self.store.WRITE_CHUNKSIZE
+        expected_s3_contents = b"*" * total_size
+        image_s3 = io.BytesIO(expected_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+        # Patch abort_multipart_upload on the client to a Mock
+        fake_s3_client.abort_multipart_upload = mock.Mock()
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='create_multipart_upload',
+                                 service_response={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                     "UploadId": 'UploadId'
+                                 },
+                                 expected_params={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                 })
+            stubber.add_response(method='abort_multipart_upload',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'UploadId': 'UploadId'
+                                 })
+
+            mock_client.return_value = fake_s3_client
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, expected_image_id, image_s3,
+                expected_s3_size, self.hash_algo)
+
+            # Verify that the stream's position reflects the number of bytes
+            # read, which should be exactly at expected_file_size plus the
+            # last buffer size read.
+            actual_read_size = image_s3.tell()
+            self.assertEqual(actual_read_size, total_size,
+                             "The stream was not read only up to the expected "
+                             "size.")
+
+            # Assert that abort_multipart_upload was called
+            fake_s3_client.abort_multipart_upload.assert_called_once_with(
+                Bucket=S3_CONF['s3_store_bucket'],
+                Key=expected_image_id,
+                UploadId='UploadId'
+            )
+
+    @mock.patch.object(boto3.session.Session, "client")
+    def test_add_multipart_write_less_than_declared(self, mock_client):
+        """Test size validation during multipart upload."""
+        expected_image_id = str(uuid.uuid4())
+        expected_s3_size = 16 * units.Mi
+        # Actual data is less than expected to trigger size validation
+        # failure, 1MB less
+        expected_s3_contents = b"*" * (expected_s3_size - 1 * units.Mi)
+        image_s3 = io.BytesIO(expected_s3_contents)
+
+        fake_s3_client = botocore.session.get_session().create_client('s3')
+        # Patch abort_multipart_upload on the client to a Mock
+        fake_s3_client.abort_multipart_upload = mock.Mock()
+        with stub.Stubber(fake_s3_client) as stubber:
+            stubber.add_response(method='head_bucket',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket']
+                                 })
+            stubber.add_client_error(method='head_object',
+                                     service_error_code='404',
+                                     service_message='',
+                                     expected_params={
+                                         'Bucket': S3_CONF['s3_store_bucket'],
+                                         'Key': expected_image_id
+                                     })
+            stubber.add_response(method='create_multipart_upload',
+                                 service_response={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                     "UploadId": 'UploadId'
+                                 },
+                                 expected_params={
+                                     "Bucket": S3_CONF['s3_store_bucket'],
+                                     "Key": expected_image_id,
+                                 })
+            stubber.add_response(method='abort_multipart_upload',
+                                 service_response={},
+                                 expected_params={
+                                     'Bucket': S3_CONF['s3_store_bucket'],
+                                     'Key': expected_image_id,
+                                     'UploadId': 'UploadId'
+                                 })
+
+            mock_client.return_value = fake_s3_client
+            # Expect an exception due to size mismatch
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size mismatch: expected",
+                self.store.add, expected_image_id, image_s3,
+                expected_s3_size, self.hash_algo)
+
+            # The input buffer should be fully read depending on implementation
+            total_input_size = len(expected_s3_contents)
+            self.assertEqual(image_s3.tell(), total_input_size)
+
+            # Assert that abort_multipart_upload was called
+            fake_s3_client.abort_multipart_upload.assert_called_once_with(
+                Bucket=S3_CONF['s3_store_bucket'],
+                Key=expected_image_id,
+                UploadId='UploadId'
+            )
+
+    @mock.patch.object(boto3.session.Session, "client")
     def test_add_already_existing(self, mock_client):
         """Tests that adding an image with an existing identifier
         raises an appropriate exception
diff -pruN 4.9.1-2/glance_store/tests/unit/test_swift_store.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_swift_store.py
--- 4.9.1-2/glance_store/tests/unit/test_swift_store.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_swift_store.py	2025-07-10 09:13:16.000000000 +0000
@@ -27,7 +27,6 @@ import tempfile
 import uuid
 
 from oslo_config import cfg
-from oslo_utils import encodeutils
 from oslo_utils import units
 import requests_mock
 import swiftclient
@@ -70,9 +69,18 @@ class SwiftTests(object):
 
     def mock_keystone_client(self):
         # mock keystone client functions to avoid dependency errors
-        swift.ks_v3 = mock.MagicMock()
-        swift.ks_session = mock.MagicMock()
-        swift.ks_client = mock.MagicMock()
+        ks_identity_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_identity')
+        self.mock_identity = ks_identity_patcher.start()
+        self.addCleanup(ks_identity_patcher.stop)
+        ks_session_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_session')
+        self.mock_session = ks_session_patcher.start()
+        self.addCleanup(ks_session_patcher.stop)
+        ks_client_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_client')
+        self.mock_client = ks_client_patcher.start()
+        self.addCleanup(ks_client_patcher.stop)
 
     def stub_out_swiftclient(self, swift_store_auth_version):
         fixture_containers = ['glance']
@@ -452,6 +460,62 @@ class SwiftTests(object):
         self.assertEqual(expected_swift_contents, new_image_contents)
         self.assertEqual(expected_swift_size, new_image_swift_size)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        """Test that we can add an image via the swift backend."""
+        importlib.reload(swift)
+        self.mock_keystone_client()
+        self.config()
+        self.store = Store(self.conf)
+        self.store.configure()
+        expected_swift_size = FIVE_KB
+        # 1KB more data than actual expected size
+        expected_swift_contents = b"*" * (expected_swift_size + units.Ki)
+        expected_image_id = str(uuid.uuid4())
+        custom_size = units.Ki
+        self.store.large_object_size = custom_size
+        self.store.large_object_chunk_size = custom_size
+
+        image_swift = io.BytesIO(expected_swift_contents)
+
+        with mock.patch.object(self.store,
+                               '_delete_stale_chunks') as mock_delete:
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, expected_image_id, image_swift,
+                expected_swift_size, HASH_ALGO)
+
+        # The position should be equal to total input size
+        self.assertEqual(image_swift.tell(), len(expected_swift_contents))
+        mock_delete.assert_called_once()
+
+    def test_write_less_than_declared_raises_exception(self):
+        """Test that we can add an image via the swift backend."""
+        importlib.reload(swift)
+        self.mock_keystone_client()
+        self.config()
+        self.store = Store(self.conf)
+        self.store.configure()
+        expected_swift_size = FIVE_KB
+        # 1KB fewer data than actual expected size
+        expected_swift_contents = b"*" * (expected_swift_size - units.Ki)
+        expected_image_id = str(uuid.uuid4())
+        custom_size = units.Ki
+        self.store.large_object_size = custom_size
+        self.store.large_object_chunk_size = custom_size
+
+        image_swift = io.BytesIO(expected_swift_contents)
+
+        with mock.patch.object(self.store,
+                               '_delete_stale_chunks') as mock_delete:
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size mismatch: expected",
+                self.store.add, expected_image_id, image_swift,
+                expected_swift_size, HASH_ALGO)
+
+        # The position should be equal to actual data size
+        self.assertEqual(image_swift.tell(), len(expected_swift_contents))
+        mock_delete.assert_called_once()
+
     def test_add_multi_store(self):
 
         conf = copy.deepcopy(SWIFT_CONF)
@@ -624,17 +688,10 @@ class SwiftTests(object):
         global SWIFT_PUT_OBJECT_CALLS
         SWIFT_PUT_OBJECT_CALLS = 0
 
-        # We check the exception text to ensure the container
-        # missing text is found in it, otherwise, we would have
-        # simply used self.assertRaises here
-        exception_caught = False
-        try:
-            self.store.add(str(uuid.uuid4()), image_swift, 0, HASH_ALGO)
-        except exceptions.BackendException as e:
-            exception_caught = True
-            self.assertIn("container noexist does not exist in Swift",
-                          encodeutils.exception_to_unicode(e))
-        self.assertTrue(exception_caught)
+        msg = "container noexist does not exist in Swift"
+        self.assertRaisesRegex(exceptions.BackendException, msg,
+                               self.store.add, str(uuid.uuid4()),
+                               image_swift, 0, HASH_ALGO)
         self.assertEqual(0, SWIFT_PUT_OBJECT_CALLS)
 
     @mock.patch('glance_store._drivers.swift.utils'
@@ -762,18 +819,11 @@ class SwiftTests(object):
         global SWIFT_PUT_OBJECT_CALLS
         SWIFT_PUT_OBJECT_CALLS = 0
 
-        # We check the exception text to ensure the container
-        # missing text is found in it, otherwise, we would have
-        # simply used self.assertRaises here
-        exception_caught = False
-        try:
-            self.store.add(expected_image_id, image_swift, 0, HASH_ALGO)
-        except exceptions.BackendException as e:
-            exception_caught = True
-            expected_msg = "container %s does not exist in Swift"
-            expected_msg = expected_msg % expected_container
-            self.assertIn(expected_msg, encodeutils.exception_to_unicode(e))
-        self.assertTrue(exception_caught)
+        expected_msg = "container %s does not exist in Swift"
+        expected_msg = expected_msg % expected_container
+        self.assertRaisesRegex(exceptions.BackendException, expected_msg,
+                               self.store.add, expected_image_id,
+                               image_swift, 0, HASH_ALGO)
         self.assertEqual(0, SWIFT_PUT_OBJECT_CALLS)
 
     @mock.patch('glance_store._drivers.swift.utils'
@@ -1309,11 +1359,7 @@ class SwiftTests(object):
                           swift_store_auth_insecure=True,
                           swift_store_config_file=None)
 
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def _init_client(self, mock_client, mock_session, mock_identity, verify,
-                     **kwargs):
+    def _init_client(self, verify, **kwargs):
         # initialize store and connection parameters
         self.config(**kwargs)
         store = Store(self.conf)
@@ -1334,25 +1380,27 @@ class SwiftTests(object):
         trustor_client.trusts.create.return_value = mock.MagicMock(
             id='fake_trust')
         main_client = mock.MagicMock()
-        mock_session.Session.side_effect = [trustor_session, trustee_session,
-                                            main_session]
-        mock_client.Client.side_effect = [trustor_client, trustee_client,
-                                          main_client]
+        self.mock_session.Session.side_effect = [
+            trustor_session, trustee_session, main_session]
+        self.mock_client.Client.side_effect = [
+            trustor_client, trustee_client, main_client]
+
         # initialize client
         ctxt = mock.MagicMock()
         client = store.init_client(location=mock.MagicMock(), context=ctxt)
         # test trustor usage
-        mock_identity.V3Token.assert_called_once_with(
+        self.mock_identity.V3Token.assert_called_once_with(
             auth_url=default_swift_reference.get('auth_address'),
             token=ctxt.auth_token,
             project_id=ctxt.project_id
         )
-        mock_session.Session.assert_any_call(auth=mock_identity.V3Token(),
-                                             verify=verify)
-        mock_client.Client.assert_any_call(session=trustor_session)
+        self.mock_session.Session.assert_any_call(
+            auth=self.mock_identity.V3Token(),
+            verify=verify)
+        self.mock_client.Client.assert_any_call(session=trustor_session)
         # test trustee usage and trust creation
         tenant_name, user = default_swift_reference.get('user').split(':')
-        mock_identity.V3Password.assert_any_call(
+        self.mock_identity.V3Password.assert_any_call(
             auth_url=default_swift_reference.get('auth_address'),
             username=user,
             password=default_swift_reference.get('key'),
@@ -1363,15 +1411,16 @@ class SwiftTests(object):
             project_domain_name=default_swift_reference.get(
                 'project_domain_name')
         )
-        mock_session.Session.assert_any_call(auth=mock_identity.V3Password(),
-                                             verify=verify)
-        mock_client.Client.assert_any_call(session=trustee_session)
+        self.mock_session.Session.assert_any_call(
+            auth=self.mock_identity.V3Password(),
+            verify=verify)
+        self.mock_client.Client.assert_any_call(session=trustee_session)
         trustor_client.trusts.create.assert_called_once_with(
             trustee_user='fake_user', trustor_user=ctxt.user_id,
             project=ctxt.project_id, impersonation=True,
             role_names=['fake_role']
         )
-        mock_identity.V3Password.assert_any_call(
+        self.mock_identity.V3Password.assert_any_call(
             auth_url=default_swift_reference.get('auth_address'),
             username=user,
             password=default_swift_reference.get('key'),
@@ -1382,31 +1431,30 @@ class SwiftTests(object):
             project_domain_name=default_swift_reference.get(
                 'project_domain_name')
         )
-        mock_client.Client.assert_any_call(session=main_session)
+        self.mock_client.Client.assert_any_call(session=main_session)
         self.assertEqual(main_client, client)
 
 
-class TestStoreAuthV1(base.StoreBaseTest, SwiftTests,
+class TestStoreAuthV3(base.StoreBaseTest, SwiftTests,
                       test_store_capabilities.TestStoreCapabilitiesChecking):
 
     _CONF = cfg.CONF
 
     def getConfig(self):
         conf = SWIFT_CONF.copy()
-        conf['swift_store_auth_version'] = '1'
         conf['swift_store_user'] = 'tenant:user1'
         return conf
 
     def setUp(self):
         """Establish a clean test environment."""
-        super(TestStoreAuthV1, self).setUp()
+        super(TestStoreAuthV3, self).setUp()
         conf = self.getConfig()
 
         conf_file = 'glance-swift.conf'
         self.swift_config_file = self.copy_data_file(conf_file, self.test_dir)
         conf.update({'swift_store_config_file': self.swift_config_file})
 
-        self.stub_out_swiftclient(conf['swift_store_auth_version'])
+        self.stub_out_swiftclient('3')
         self.mock_keystone_client()
         self.store = Store(self.conf)
         self.config(**conf)
@@ -1414,45 +1462,7 @@ class TestStoreAuthV1(base.StoreBaseTest
         self.register_store_schemes(self.store, 'swift')
         self.addCleanup(self.conf.reset)
 
-
-class TestStoreAuthV2(TestStoreAuthV1):
-
-    def getConfig(self):
-        conf = super(TestStoreAuthV2, self).getConfig()
-        conf['swift_store_auth_version'] = '2'
-        conf['swift_store_user'] = 'tenant:user1'
-        return conf
-
-    def test_v2_with_no_tenant(self):
-        uri = "swift://failme:key@auth_address/glance/%s" % (FAKE_UUID)
-        loc = location.get_location_from_uri(uri, conf=self.conf)
-        self.assertRaises(exceptions.BadStoreUri,
-                          self.store.get,
-                          loc)
-
-    def test_v2_multi_tenant_location(self):
-        conf = self.getConfig()
-        conf['swift_store_multi_tenant'] = True
-        uri = "swift://auth_address/glance/%s" % (FAKE_UUID)
-        loc = location.get_location_from_uri(uri, conf=self.conf)
-        self.assertEqual('swift', loc.store_name)
-
-
-class TestStoreAuthV3(TestStoreAuthV1):
-
-    def getConfig(self):
-        conf = super(TestStoreAuthV3, self).getConfig()
-        conf['swift_store_auth_version'] = '3'
-        conf['swift_store_user'] = 'tenant:user1'
-        return conf
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant(self,
-                                       mock_client,
-                                       mock_session,
-                                       mock_identity):
+    def test_init_client_single_tenant(self):
         """Test that keystone client was initialized correctly"""
         # initialize client
         store = Store(self.conf)
@@ -1462,24 +1472,18 @@ class TestStoreAuthV3(TestStoreAuthV1):
         loc = location.get_location_from_uri(uri, conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id='default', project_domain_name=None,
             user_domain_id='default', user_domain_name=None,)
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant_with_domain_ids(self,
-                                                       mock_client,
-                                                       mock_session,
-                                                       mock_identity):
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
+
+    def test_init_client_single_tenant_with_domain_ids(self):
         """Test that keystone client was initialized correctly"""
         # initialize client
         conf = self.getConfig()
@@ -1492,24 +1496,18 @@ class TestStoreAuthV3(TestStoreAuthV1):
         loc = location.get_location_from_uri(uri, conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id='projdomainid', project_domain_name=None,
             user_domain_id='userdomainid', user_domain_name=None,)
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant_with_domain_names(self,
-                                                         mock_client,
-                                                         mock_session,
-                                                         mock_identity):
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
+
+    def test_init_client_single_tenant_with_domain_names(self):
         """Test that keystone client was initialized correctly"""
         # initialize client
         conf = self.getConfig()
@@ -1522,16 +1520,16 @@ class TestStoreAuthV3(TestStoreAuthV1):
         loc = location.get_location_from_uri(uri, conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id=None, project_domain_name='projdomain',
             user_domain_id=None, user_domain_name='userdomain',)
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
 
 
 class FakeConnection(object):
@@ -1564,7 +1562,7 @@ class TestSingleTenantStoreConnections(b
         self.store = swift.SingleTenantStore(self.conf)
         self.store.configure()
         specs = {'scheme': 'swift',
-                 'auth_or_store_url': 'example.com/v2/',
+                 'auth_or_store_url': 'example.com/v3/',
                  'user': 'tenant:user1',
                  'key': 'key1',
                  'container': 'cont',
@@ -1572,79 +1570,32 @@ class TestSingleTenantStoreConnections(b
         self.location = swift.StoreLocation(specs, self.conf)
         self.addCleanup(self.conf.reset)
 
-    def test_basic_connection(self):
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertIsNone(connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
-
-    def test_connection_with_conf_endpoint(self):
-        ctx = mock.MagicMock(user='tenant:user1', tenant='tenant')
-        self.config(swift_store_endpoint='https://internal.com')
-        self.store.configure()
-        connection = self.store.get_connection(self.location, context=ctx)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertEqual('https://internal.com', connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
-
-    def test_connection_with_conf_endpoint_no_context(self):
-        self.config(swift_store_endpoint='https://internal.com')
-        self.store.configure()
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertEqual('https://internal.com', connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
-
     @mock.patch("keystoneauth1.session.Session.get_endpoint")
     @mock.patch("keystoneauth1.session.Session.get_auth_headers",
                 new=mock.Mock())
     def _test_connection_manager_authv3_conf_endpoint(
             self, mock_ep, expected_endpoint="https://from-catalog.com"):
-        self.config(swift_store_auth_version='3')
         mock_ep.return_value = "https://from-catalog.com"
-        ctx = mock.MagicMock()
         self.store.configure()
         connection_manager = manager.SingleTenantConnectionManager(
             store=self.store,
             store_location=self.location,
-            context=ctx
         )
         conn = connection_manager._init_connection()
         self.assertEqual(expected_endpoint, conn.preauthurl)
 
-    def test_connection_manager_authv3_without_conf_endpoint(self):
+    def test_connection_manager_without_conf_endpoint(self):
         self._test_connection_manager_authv3_conf_endpoint()
 
-    def test_connection_manager_authv3_with_conf_endpoint(self):
+    def test_connection_manager_with_conf_endpoint(self):
         self.config(swift_store_endpoint='http://localhost')
         self._test_connection_manager_authv3_conf_endpoint(
             expected_endpoint='http://localhost')
 
     def test_connection_with_no_trailing_slash(self):
-        self.location.auth_or_store_url = 'example.com/v2'
+        self.location.auth_or_store_url = 'example.com/v3'
         connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
+        self.assertEqual('https://example.com/v3/', connection.authurl)
 
     def test_connection_insecure(self):
         self.config(swift_store_auth_insecure=True)
@@ -1652,15 +1603,6 @@ class TestSingleTenantStoreConnections(b
         connection = self.store.get_connection(self.location)
         self.assertTrue(connection.insecure)
 
-    def test_connection_with_auth_v1(self):
-        self.config(swift_store_auth_version='1')
-        self.store.configure()
-        self.location.user = 'auth_v1_user'
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('1', connection.auth_version)
-        self.assertEqual('auth_v1_user', connection.user)
-        self.assertIsNone(connection.tenant_name)
-
     def test_connection_invalid_user(self):
         self.store.configure()
         self.location.user = 'invalid:format:user'
@@ -1720,8 +1662,7 @@ class TestSingleTenantStoreConnections(b
                           self.location.uri)
 
     def test_ref_overrides_defaults(self):
-        self.config(swift_store_auth_version='2',
-                    swift_store_user='testuser',
+        self.config(swift_store_user='testuser',
                     swift_store_key='testpass',
                     swift_store_auth_address='testaddress',
                     swift_store_endpoint_type='internalURL',
diff -pruN 4.9.1-2/glance_store/tests/unit/test_swift_store_multibackend.py 5.0.0-0ubuntu2/glance_store/tests/unit/test_swift_store_multibackend.py
--- 4.9.1-2/glance_store/tests/unit/test_swift_store_multibackend.py	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store/tests/unit/test_swift_store_multibackend.py	2025-07-10 09:13:16.000000000 +0000
@@ -27,7 +27,6 @@ import tempfile
 import uuid
 
 from oslo_config import cfg
-from oslo_utils import encodeutils
 from oslo_utils import units
 import requests_mock
 import swiftclient
@@ -66,9 +65,18 @@ class SwiftTests(object):
 
     def mock_keystone_client(self):
         # mock keystone client functions to avoid dependency errors
-        swift.ks_v3 = mock.MagicMock()
-        swift.ks_session = mock.MagicMock()
-        swift.ks_client = mock.MagicMock()
+        ks_identity_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_identity')
+        self.mock_identity = ks_identity_patcher.start()
+        self.addCleanup(ks_identity_patcher.stop)
+        ks_session_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_session')
+        self.mock_session = ks_session_patcher.start()
+        self.addCleanup(ks_session_patcher.stop)
+        ks_client_patcher = mock.patch(
+            'glance_store._drivers.swift.store.ks_client')
+        self.mock_client = ks_client_patcher.start()
+        self.addCleanup(ks_client_patcher.stop)
 
     def stub_out_swiftclient(self, swift_store_auth_version):
         fixture_containers = ['glance']
@@ -425,6 +433,62 @@ class SwiftTests(object):
         self.assertEqual(expected_swift_contents, new_image_contents)
         self.assertEqual(expected_swift_size, new_image_swift_size)
 
+    def test_add_image_exceeding_max_size_raises_exception(self):
+        """Test that we can add an image via the swift backend."""
+        importlib.reload(swift)
+        self.mock_keystone_client()
+        self.config()
+        self.store = Store(self.conf, backend="swift1")
+        self.store.configure()
+        expected_swift_size = FIVE_KB
+        # 1KB more data than actual expected size
+        expected_swift_contents = b"*" * (expected_swift_size + units.Ki)
+        expected_image_id = str(uuid.uuid4())
+        custom_size = units.Ki
+        self.store.large_object_size = custom_size
+        self.store.large_object_chunk_size = custom_size
+
+        image_swift = io.BytesIO(expected_swift_contents)
+
+        with mock.patch.object(self.store,
+                               '_delete_stale_chunks') as mock_delete:
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size exceeds: expected",
+                self.store.add, expected_image_id, image_swift,
+                expected_swift_size)
+
+        # The position should be equal to total input size
+        self.assertEqual(image_swift.tell(), len(expected_swift_contents))
+        mock_delete.assert_called_once()
+
+    def test_write_less_than_declared_raises_exception(self):
+        """Test that we can add an image via the swift backend."""
+        importlib.reload(swift)
+        self.mock_keystone_client()
+        self.config()
+        self.store = Store(self.conf, backend="swift1")
+        self.store.configure()
+        expected_swift_size = FIVE_KB
+        # 1KB fewer data than actual expected size
+        expected_swift_contents = b"*" * (expected_swift_size - units.Ki)
+        expected_image_id = str(uuid.uuid4())
+        custom_size = units.Ki
+        self.store.large_object_size = custom_size
+        self.store.large_object_chunk_size = custom_size
+
+        image_swift = io.BytesIO(expected_swift_contents)
+
+        with mock.patch.object(self.store,
+                               '_delete_stale_chunks') as mock_delete:
+            self.assertRaisesRegex(
+                exceptions.Invalid, "Size mismatch: expected",
+                self.store.add, expected_image_id, image_swift,
+                expected_swift_size)
+
+        # The position should be equal to actual data size
+        self.assertEqual(image_swift.tell(), len(expected_swift_contents))
+        mock_delete.assert_called_once()
+
     def test_add_multi_store(self):
 
         conf = copy.deepcopy(SWIFT_CONF)
@@ -574,17 +638,10 @@ class SwiftTests(object):
         global SWIFT_PUT_OBJECT_CALLS
         SWIFT_PUT_OBJECT_CALLS = 0
 
-        # We check the exception text to ensure the container
-        # missing text is found in it, otherwise, we would have
-        # simply used self.assertRaises here
-        exception_caught = False
-        try:
-            self.store.add(str(uuid.uuid4()), image_swift, 0)
-        except exceptions.BackendException as e:
-            exception_caught = True
-            self.assertIn("container noexist does not exist in Swift",
-                          encodeutils.exception_to_unicode(e))
-        self.assertTrue(exception_caught)
+        msg = "container noexist does not exist in Swift"
+        self.assertRaisesRegex(exceptions.BackendException, msg,
+                               self.store.add, str(uuid.uuid4()),
+                               image_swift, 0)
         self.assertEqual(0, SWIFT_PUT_OBJECT_CALLS)
 
     @mock.patch('glance_store._drivers.swift.utils'
@@ -712,18 +769,11 @@ class SwiftTests(object):
         global SWIFT_PUT_OBJECT_CALLS
         SWIFT_PUT_OBJECT_CALLS = 0
 
-        # We check the exception text to ensure the container
-        # missing text is found in it, otherwise, we would have
-        # simply used self.assertRaises here
-        exception_caught = False
-        try:
-            self.store.add(expected_image_id, image_swift, 0)
-        except exceptions.BackendException as e:
-            exception_caught = True
-            expected_msg = "container %s does not exist in Swift"
-            expected_msg = expected_msg % expected_container
-            self.assertIn(expected_msg, encodeutils.exception_to_unicode(e))
-        self.assertTrue(exception_caught)
+        expected_msg = "container %s does not exist in Swift"
+        expected_msg = expected_msg % expected_container
+        self.assertRaisesRegex(exceptions.BackendException, expected_msg,
+                               self.store.add, expected_image_id,
+                               image_swift, 0)
         self.assertEqual(0, SWIFT_PUT_OBJECT_CALLS)
 
     @mock.patch('glance_store._drivers.swift.utils'
@@ -1279,11 +1329,7 @@ class SwiftTests(object):
                               swift_store_auth_insecure=True,
                               swift_store_config_file=None)
 
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def _init_client(self, mock_client, mock_session, mock_identity, verify,
-                     **kwargs):
+    def _init_client(self, verify, **kwargs):
         # initialize store and connection parameters
         self.config(group="swift1", **kwargs)
         store = Store(self.conf, backend="swift1")
@@ -1304,25 +1350,26 @@ class SwiftTests(object):
         trustor_client.trusts.create.return_value = mock.MagicMock(
             id='fake_trust')
         main_client = mock.MagicMock()
-        mock_session.Session.side_effect = [trustor_session, trustee_session,
-                                            main_session]
-        mock_client.Client.side_effect = [trustor_client, trustee_client,
-                                          main_client]
+        self.mock_session.Session.side_effect = [
+            trustor_session, trustee_session, main_session]
+        self.mock_client.Client.side_effect = [
+            trustor_client, trustee_client, main_client]
         # initialize client
         ctxt = mock.MagicMock()
         client = store.init_client(location=mock.MagicMock(), context=ctxt)
         # test trustor usage
-        mock_identity.V3Token.assert_called_once_with(
+        self.mock_identity.V3Token.assert_called_once_with(
             auth_url=default_swift_reference.get('auth_address'),
             token=ctxt.auth_token,
             project_id=ctxt.project_id
         )
-        mock_session.Session.assert_any_call(auth=mock_identity.V3Token(),
-                                             verify=verify)
-        mock_client.Client.assert_any_call(session=trustor_session)
+        self.mock_session.Session.assert_any_call(
+            auth=self.mock_identity.V3Token(),
+            verify=verify)
+        self.mock_client.Client.assert_any_call(session=trustor_session)
         # test trustee usage and trust creation
         tenant_name, user = default_swift_reference.get('user').split(':')
-        mock_identity.V3Password.assert_any_call(
+        self.mock_identity.V3Password.assert_any_call(
             auth_url=default_swift_reference.get('auth_address'),
             username=user,
             password=default_swift_reference.get('key'),
@@ -1333,15 +1380,16 @@ class SwiftTests(object):
             project_domain_name=default_swift_reference.get(
                 'project_domain_name')
         )
-        mock_session.Session.assert_any_call(auth=mock_identity.V3Password(),
-                                             verify=verify)
-        mock_client.Client.assert_any_call(session=trustee_session)
+        self.mock_session.Session.assert_any_call(
+            auth=self.mock_identity.V3Password(),
+            verify=verify)
+        self.mock_client.Client.assert_any_call(session=trustee_session)
         trustor_client.trusts.create.assert_called_once_with(
             trustee_user='fake_user', trustor_user=ctxt.user_id,
             project=ctxt.project_id, impersonation=True,
             role_names=['fake_role']
         )
-        mock_identity.V3Password.assert_any_call(
+        self.mock_identity.V3Password.assert_any_call(
             auth_url=default_swift_reference.get('auth_address'),
             username=user,
             password=default_swift_reference.get('key'),
@@ -1352,11 +1400,11 @@ class SwiftTests(object):
             project_domain_name=default_swift_reference.get(
                 'project_domain_name')
         )
-        mock_client.Client.assert_any_call(session=main_session)
+        self.mock_client.Client.assert_any_call(session=main_session)
         self.assertEqual(main_client, client)
 
 
-class TestStoreAuthV1(base.MultiStoreBaseTest, SwiftTests,
+class TestStoreAuthV3(base.MultiStoreBaseTest, SwiftTests,
                       test_store_capabilities.TestStoreCapabilitiesChecking):
 
     # NOTE(flaper87): temporary until we
@@ -1366,13 +1414,13 @@ class TestStoreAuthV1(base.MultiStoreBas
 
     def getConfig(self):
         conf = SWIFT_CONF.copy()
-        conf['swift_store_auth_version'] = '1'
+        conf['swift_store_auth_version'] = '3'
         conf['swift_store_user'] = 'tenant:user1'
         return conf
 
     def setUp(self):
         """Establish a clean test environment."""
-        super(TestStoreAuthV1, self).setUp()
+        super(TestStoreAuthV3, self).setUp()
         enabled_backends = {
             "swift1": "swift",
             "swift2": "swift",
@@ -1407,48 +1455,7 @@ class TestStoreAuthV1(base.MultiStoreBas
         self.register_store_backend_schemes(self.store, 'swift', 'swift1')
         self.addCleanup(self.conf.reset)
 
-
-class TestStoreAuthV2(TestStoreAuthV1):
-
-    def getConfig(self):
-        config = super(TestStoreAuthV2, self).getConfig()
-        config['swift_store_auth_version'] = '2'
-        config['swift_store_user'] = 'tenant:user1'
-        return config
-
-    def test_v2_with_no_tenant(self):
-        uri = "swift://failme:key@auth_address/glance/%s" % (FAKE_UUID)
-        loc = location.get_location_from_uri_and_backend(
-            uri, "swift1", conf=self.conf)
-        self.assertRaises(exceptions.BadStoreUri,
-                          self.store.get,
-                          loc)
-
-    def test_v2_multi_tenant_location(self):
-        config = self.getConfig()
-        config['swift_store_multi_tenant'] = True
-        self.config(group="swift1", **config)
-        uri = "swift://auth_address/glance/%s" % (FAKE_UUID)
-        loc = location.get_location_from_uri_and_backend(
-            uri, "swift1", conf=self.conf)
-        self.assertEqual('swift', loc.store_name)
-
-
-class TestStoreAuthV3(TestStoreAuthV1):
-
-    def getConfig(self):
-        config = super(TestStoreAuthV3, self).getConfig()
-        config['swift_store_auth_version'] = '3'
-        config['swift_store_user'] = 'tenant:user1'
-        return config
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant(self,
-                                       mock_client,
-                                       mock_session,
-                                       mock_identity):
+    def test_init_client_single_tenant(self):
         """Test that keystone client was initialized correctly"""
         # initialize client
         store = Store(self.conf, backend="swift1")
@@ -1459,24 +1466,18 @@ class TestStoreAuthV3(TestStoreAuthV1):
             uri, "swift1", conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id='default', project_domain_name=None,
             user_domain_id='default', user_domain_name=None,)
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant_with_domain_ids(self,
-                                                       mock_client,
-                                                       mock_session,
-                                                       mock_identity):
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
+
+    def test_init_client_single_tenant_with_domain_ids(self):
         """Test that keystone client was initialized correctly"""
         conf = self.getConfig()
         conf['default_swift_reference'] = 'ref4'
@@ -1489,24 +1490,18 @@ class TestStoreAuthV3(TestStoreAuthV1):
             uri, "swift1", conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id='projdomainid', project_domain_name=None,
             user_domain_id='userdomainid', user_domain_name=None)
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
-
-    @mock.patch("glance_store._drivers.swift.store.ks_identity")
-    @mock.patch("glance_store._drivers.swift.store.ks_session")
-    @mock.patch("glance_store._drivers.swift.store.ks_client")
-    def test_init_client_single_tenant_with_domain_names(self,
-                                                         mock_client,
-                                                         mock_session,
-                                                         mock_identity):
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
+
+    def test_init_client_single_tenant_with_domain_names(self):
         """Test that keystone client was initialized correctly"""
         conf = self.getConfig()
         conf['default_swift_reference'] = 'ref5'
@@ -1519,16 +1514,16 @@ class TestStoreAuthV3(TestStoreAuthV1):
             uri, "swift1", conf=self.conf)
         ctxt = mock.MagicMock()
         store.init_client(location=loc.store_location, context=ctxt)
-        mock_identity.V3Password.assert_called_once_with(
+        self.mock_identity.V3Password.assert_called_once_with(
             auth_url=loc.store_location.swift_url + '/',
             username="user1", password="key",
             project_name="tenant",
             project_domain_id=None, project_domain_name='projdomain',
             user_domain_id=None, user_domain_name='userdomain')
-        mock_session.Session.assert_called_once_with(
-            auth=mock_identity.V3Password(), verify=True)
-        mock_client.Client.assert_called_once_with(
-            session=mock_session.Session())
+        self.mock_session.Session.assert_called_once_with(
+            auth=self.mock_identity.V3Password(), verify=True)
+        self.mock_client.Client.assert_called_once_with(
+            session=self.mock_session.Session())
 
 
 class FakeConnection(object):
@@ -1584,7 +1579,7 @@ class TestSingleTenantStoreConnections(b
         self.store = swift.SingleTenantStore(self.conf, backend="swift1")
         self.store.configure()
         specs = {'scheme': 'swift',
-                 'auth_or_store_url': 'example.com/v2/',
+                 'auth_or_store_url': 'example.com/v3/',
                  'user': 'tenant:user1',
                  'key': 'key1',
                  'container': 'cont',
@@ -1595,56 +1590,32 @@ class TestSingleTenantStoreConnections(b
         self.register_store_backend_schemes(self.store, 'swift', 'swift1')
         self.addCleanup(self.conf.reset)
 
-    def test_basic_connection(self):
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertIsNone(connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
+    @mock.patch("keystoneauth1.session.Session.get_endpoint")
+    @mock.patch("keystoneauth1.session.Session.get_auth_headers",
+                new=mock.Mock())
+    def _test_connection_manager_authv3_conf_endpoint(
+            self, mock_ep, expected_endpoint="https://from-catalog.com"):
+        mock_ep.return_value = "https://from-catalog.com"
+        self.store.configure()
+        connection_manager = manager.SingleTenantConnectionManager(
+            store=self.store,
+            store_location=self.location,
+        )
+        conn = connection_manager._init_connection()
+        self.assertEqual(expected_endpoint, conn.preauthurl)
 
-    def test_connection_with_conf_endpoint(self):
-        ctx = mock.MagicMock(user='tenant:user1', tenant='tenant')
-        self.config(group="swift1",
-                    swift_store_endpoint='https://internal.com')
-        self.store.configure()
-        connection = self.store.get_connection(self.location, context=ctx)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertEqual('https://internal.com', connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
+    def test_connection_manager_without_conf_endpoint(self):
+        self._test_connection_manager_authv3_conf_endpoint()
 
-    def test_connection_with_conf_endpoint_no_context(self):
-        self.config(group="swift1",
-                    swift_store_endpoint='https://internal.com')
-        self.store.configure()
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
-        self.assertEqual('2', connection.auth_version)
-        self.assertEqual('user1', connection.user)
-        self.assertEqual('tenant', connection.tenant_name)
-        self.assertEqual('key1', connection.key)
-        self.assertEqual('https://internal.com', connection.preauthurl)
-        self.assertFalse(connection.insecure)
-        self.assertEqual({'service_type': 'object-store',
-                          'endpoint_type': 'publicURL'},
-                         connection.os_options)
+    def test_connection_manager_with_conf_endpoint(self):
+        self.config(group="swift1", swift_store_endpoint='http://localhost')
+        self._test_connection_manager_authv3_conf_endpoint(
+            expected_endpoint='http://localhost')
 
     def test_connection_with_no_trailing_slash(self):
-        self.location.auth_or_store_url = 'example.com/v2'
+        self.location.auth_or_store_url = 'example.com/v3'
         connection = self.store.get_connection(self.location)
-        self.assertEqual('https://example.com/v2/', connection.authurl)
+        self.assertEqual('https://example.com/v3/', connection.authurl)
 
     def test_connection_insecure(self):
         self.config(group="swift1", swift_store_auth_insecure=True)
@@ -1652,15 +1623,6 @@ class TestSingleTenantStoreConnections(b
         connection = self.store.get_connection(self.location)
         self.assertTrue(connection.insecure)
 
-    def test_connection_with_auth_v1(self):
-        self.config(group="swift1", swift_store_auth_version='1')
-        self.store.configure()
-        self.location.user = 'auth_v1_user'
-        connection = self.store.get_connection(self.location)
-        self.assertEqual('1', connection.auth_version)
-        self.assertEqual('auth_v1_user', connection.user)
-        self.assertIsNone(connection.tenant_name)
-
     def test_connection_invalid_user(self):
         self.store.configure()
         self.location.user = 'invalid:format:user'
@@ -1720,7 +1682,7 @@ class TestSingleTenantStoreConnections(b
                           self.location.uri)
 
     def test_ref_overrides_defaults(self):
-        self.config(group="swift1", swift_store_auth_version='2',
+        self.config(group="swift1",
                     swift_store_user='testuser',
                     swift_store_key='testpass',
                     swift_store_auth_address='testaddress',
diff -pruN 4.9.1-2/glance_store.egg-info/PKG-INFO 5.0.0-0ubuntu2/glance_store.egg-info/PKG-INFO
--- 4.9.1-2/glance_store.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/PKG-INFO	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,103 @@
+Metadata-Version: 2.1
+Name: glance_store
+Version: 5.0.0
+Summary: OpenStack Image Service Store Library
+Home-page: https://docs.openstack.org/glance_store/latest/
+Author: OpenStack
+Author-email: openstack-discuss@lists.openstack.org
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Requires-Python: >=3.10
+License-File: LICENSE
+Requires-Dist: oslo.config>=5.2.0
+Requires-Dist: oslo.i18n>=3.15.3
+Requires-Dist: oslo.serialization!=2.19.1,>=2.18.0
+Requires-Dist: oslo.utils>=4.7.0
+Requires-Dist: oslo.concurrency>=3.26.0
+Requires-Dist: stevedore>=1.20.0
+Requires-Dist: eventlet!=0.18.3,!=0.20.1,>=0.18.2
+Requires-Dist: jsonschema>=3.2.0
+Requires-Dist: keystoneauth1>=3.4.0
+Requires-Dist: python-keystoneclient>=3.8.0
+Requires-Dist: requests>=2.14.2
+Provides-Extra: vmware
+Requires-Dist: oslo.vmware>=3.6.0; extra == "vmware"
+Provides-Extra: swift
+Requires-Dist: python-swiftclient>=3.2.0; extra == "swift"
+Provides-Extra: cinder
+Requires-Dist: python-cinderclient>=4.1.0; extra == "cinder"
+Requires-Dist: os-brick>=6.3.0; extra == "cinder"
+Requires-Dist: oslo.rootwrap>=5.8.0; extra == "cinder"
+Requires-Dist: oslo.privsep>=1.23.0; extra == "cinder"
+Provides-Extra: s3
+Requires-Dist: boto3>=1.9.199; extra == "s3"
+Provides-Extra: test
+Requires-Dist: hacking<6.2.0,>=6.1.0; extra == "test"
+Requires-Dist: doc8>=0.6.0; extra == "test"
+Requires-Dist: coverage!=4.4,>=4.0; extra == "test"
+Requires-Dist: ddt>=1.4.4; extra == "test"
+Requires-Dist: fixtures>=3.0.0; extra == "test"
+Requires-Dist: requests-mock>=1.2.0; extra == "test"
+Requires-Dist: retrying>=1.3.3; extra == "test"
+Requires-Dist: stestr>=2.0.0; extra == "test"
+Requires-Dist: testscenarios>=0.4; extra == "test"
+Requires-Dist: testtools>=2.2.0; extra == "test"
+Requires-Dist: oslotest>=3.2.0; extra == "test"
+Requires-Dist: openstacksdk>=0.10.0; extra == "test"
+Requires-Dist: boto3>=1.9.199; extra == "test"
+Requires-Dist: oslo.vmware>=3.6.0; extra == "test"
+Requires-Dist: httplib2>=0.9.1; extra == "test"
+Requires-Dist: python-swiftclient>=3.2.0; extra == "test"
+Requires-Dist: python-cinderclient>=4.1.0; extra == "test"
+Requires-Dist: os-brick>=2.6.0; extra == "test"
+Requires-Dist: oslo.rootwrap>=5.8.0; extra == "test"
+Requires-Dist: oslo.privsep>=1.23.0; extra == "test"
+
+========================
+Team and repository tags
+========================
+
+.. image:: https://governance.openstack.org/tc/badges/glance_store.svg
+    :target: https://governance.openstack.org/tc/reference/tags/index.html
+    :alt: The following tags have been asserted for the Glance Store
+          Library:
+          "project:official",
+          "stable:follows-policy",
+          "vulnerability:managed".
+          Follow the link for an explanation of these tags.
+.. NOTE(rosmaita): the alt text above will have to be updated when
+   additional tags are asserted for glance_store.  (The SVG in the
+   governance repo is updated automatically.)
+
+.. Change things from this point on
+
+Glance Store Library
+====================
+
+Glance's stores library
+
+This library has been extracted from the Glance source code for the
+specific use of the Glance and Glare projects.
+
+The API it exposes is not stable, has some shortcomings, and is not a
+general purpose interface. We would eventually like to change this,
+but for now using this library outside of Glance or Glare will not be
+supported by the core team.
+
+* License: Apache License, Version 2.0
+* Documentation: https://docs.openstack.org/glance_store/latest/
+* Source: https://opendev.org/openstack/glance_store/
+* Bugs: https://bugs.launchpad.net/glance-store
+* Release notes: https://docs.openstack.org/releasenotes/glance_store/index.html
+
diff -pruN 4.9.1-2/glance_store.egg-info/SOURCES.txt 5.0.0-0ubuntu2/glance_store.egg-info/SOURCES.txt
--- 4.9.1-2/glance_store.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/SOURCES.txt	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,203 @@
+.stestr.conf
+.zuul.yaml
+AUTHORS
+ChangeLog
+LICENSE
+README.rst
+requirements.txt
+setup.cfg
+setup.py
+test-requirements.txt
+tox.ini
+doc/requirements.txt
+doc/source/conf.py
+doc/source/index.rst
+doc/source/reference/index.rst
+doc/source/user/drivers.rst
+doc/source/user/index.rst
+etc/glance/rootwrap.conf
+etc/glance/rootwrap.d/glance_cinder_store.filters
+glance_store/__init__.py
+glance_store/backend.py
+glance_store/capabilities.py
+glance_store/driver.py
+glance_store/exceptions.py
+glance_store/i18n.py
+glance_store/location.py
+glance_store/multi_backend.py
+glance_store.egg-info/PKG-INFO
+glance_store.egg-info/SOURCES.txt
+glance_store.egg-info/dependency_links.txt
+glance_store.egg-info/entry_points.txt
+glance_store.egg-info/not-zip-safe
+glance_store.egg-info/pbr.json
+glance_store.egg-info/requires.txt
+glance_store.egg-info/top_level.txt
+glance_store/_drivers/__init__.py
+glance_store/_drivers/filesystem.py
+glance_store/_drivers/http.py
+glance_store/_drivers/rbd.py
+glance_store/_drivers/s3.py
+glance_store/_drivers/vmware_datastore.py
+glance_store/_drivers/cinder/__init__.py
+glance_store/_drivers/cinder/base.py
+glance_store/_drivers/cinder/nfs.py
+glance_store/_drivers/cinder/scaleio.py
+glance_store/_drivers/cinder/store.py
+glance_store/_drivers/swift/__init__.py
+glance_store/_drivers/swift/buffered.py
+glance_store/_drivers/swift/connection_manager.py
+glance_store/_drivers/swift/store.py
+glance_store/_drivers/swift/utils.py
+glance_store/common/__init__.py
+glance_store/common/attachment_state_manager.py
+glance_store/common/cinder_utils.py
+glance_store/common/fs_mount.py
+glance_store/common/utils.py
+glance_store/locale/en_GB/LC_MESSAGES/glance_store.po
+glance_store/locale/ko_KR/LC_MESSAGES/glance_store.po
+glance_store/tests/__init__.py
+glance_store/tests/base.py
+glance_store/tests/fakes.py
+glance_store/tests/utils.py
+glance_store/tests/etc/glance-swift.conf
+glance_store/tests/functional/README.rst
+glance_store/tests/functional/__init__.py
+glance_store/tests/functional/base.py
+glance_store/tests/functional/filesystem/__init__.py
+glance_store/tests/functional/filesystem/test_functional_filesystem.py
+glance_store/tests/functional/swift/__init__.py
+glance_store/tests/functional/swift/test_functional_swift.py
+glance_store/tests/unit/__init__.py
+glance_store/tests/unit/test_backend.py
+glance_store/tests/unit/test_backend_group_configuration.py
+glance_store/tests/unit/test_connection_manager.py
+glance_store/tests/unit/test_driver.py
+glance_store/tests/unit/test_exceptions.py
+glance_store/tests/unit/test_filesystem_store.py
+glance_store/tests/unit/test_http_store.py
+glance_store/tests/unit/test_location.py
+glance_store/tests/unit/test_multistore_filesystem.py
+glance_store/tests/unit/test_multistore_rbd.py
+glance_store/tests/unit/test_multistore_s3.py
+glance_store/tests/unit/test_multistore_vmware.py
+glance_store/tests/unit/test_opts.py
+glance_store/tests/unit/test_rbd_store.py
+glance_store/tests/unit/test_s3_store.py
+glance_store/tests/unit/test_store_base.py
+glance_store/tests/unit/test_store_capabilities.py
+glance_store/tests/unit/test_swift_store.py
+glance_store/tests/unit/test_swift_store_multibackend.py
+glance_store/tests/unit/test_swift_store_utils.py
+glance_store/tests/unit/test_test_utils.py
+glance_store/tests/unit/test_vmware_store.py
+glance_store/tests/unit/cinder/__init__.py
+glance_store/tests/unit/cinder/test_base.py
+glance_store/tests/unit/cinder/test_cinder_base.py
+glance_store/tests/unit/cinder/test_cinder_store.py
+glance_store/tests/unit/cinder/test_multistore_cinder.py
+glance_store/tests/unit/cinder/test_nfs.py
+glance_store/tests/unit/cinder/test_scaleio.py
+glance_store/tests/unit/common/__init__.py
+glance_store/tests/unit/common/test_attachment_state_manager.py
+glance_store/tests/unit/common/test_cinder_utils.py
+glance_store/tests/unit/common/test_fs_mount.py
+glance_store/tests/unit/common/test_utils.py
+releasenotes/notes/.placeholder
+releasenotes/notes/0.29.1-notes-ded2a1d473a306c7.yaml
+releasenotes/notes/Stein_final_release-c7df5838028b8c7e.yaml
+releasenotes/notes/add-backend-defaults-group-4c320deac0f234ee.yaml
+releasenotes/notes/add-store-weight-d443fbea8cc8d4c9.yaml
+releasenotes/notes/block-creating-encrypted-nfs-volumes-d0ff370ab762042e.yaml
+releasenotes/notes/bug-1620999-8b76a0ad14826197.yaml
+releasenotes/notes/bug-1820817-0ee70781918d232e.yaml
+releasenotes/notes/bug-1915602-fcc807a435d8a6bf.yaml
+releasenotes/notes/bug-1954883-3666d63a3c0233f1.yaml
+releasenotes/notes/bug-2004555-4fd67fce86c07461.yaml
+releasenotes/notes/cinder-fix-nfs-sparse-vol-create-76631ce05f86257c.yaml
+releasenotes/notes/cinder-nfs-block-qcow2-vol-4fed58b0afafc980.yaml
+releasenotes/notes/cinder-support-extend-in-use-volume-c6292f950ff75cca.yaml
+releasenotes/notes/deprecate-filesystem_store_datadirs-40c54304cae4e11a.yaml
+releasenotes/notes/deprecate-rados_connect_timeout-767ed1eaa026196e.yaml
+releasenotes/notes/deprecate-sheepdog-driver-1f9689c327f313d4.yaml
+releasenotes/notes/deprecate-store_add_to_backend-f419e5c4210613d2.yaml
+releasenotes/notes/deprecate-store_capabilities_update_min_interval-039389fa296e2494.yaml
+releasenotes/notes/deprecate-vmware-store-2f720c6074b843b0.yaml
+releasenotes/notes/drop-py-2-7-345cafc9c1d3f892.yaml
+releasenotes/notes/drop-python-3-6-and-3-7-41af87576c4fd7b1.yaml
+releasenotes/notes/fix-exception-logging-during-attach-9546e24189db83c4.yaml
+releasenotes/notes/fix-interval-in-retries-471155ff34d9f0e9.yaml
+releasenotes/notes/fix-ip-in-connector-info-36b95d9959f10f63.yaml
+releasenotes/notes/fix-legacy-image-update-49a149ec267dccb6.yaml
+releasenotes/notes/fix-rados_connect_timeout-39e5074bc1a3b65b.yaml
+releasenotes/notes/fix-rbd-lockup-3aa2bb86f7d29e19.yaml
+releasenotes/notes/fix-scaleio-download-image-2563cb2681895d0e.yaml
+releasenotes/notes/fix-wait-device-resize-c282940b71a3748e.yaml
+releasenotes/notes/fs-drv-chunk-sz-a1b2f6a72fad92d5.yaml
+releasenotes/notes/handle-sparse-image-a3ecfc4ae1c00d48.yaml
+releasenotes/notes/improved-configuration-options-3635b56aba3072c9.yaml
+releasenotes/notes/lock_path-cef9d6f5f52c3211.yaml
+releasenotes/notes/move-rootwrap-config-f2cf435c548aab5c.yaml
+releasenotes/notes/multi-store-0c004fc8aba2a25d.yaml
+releasenotes/notes/multi-tenant-store-058b67ce5b7f3bd0.yaml
+releasenotes/notes/multiattach-volume-handling-1a8446a64463f2cf.yaml
+releasenotes/notes/multihash-support-629e9cbc283a8b47.yaml
+releasenotes/notes/pike-relnote-9f547df14184d18c.yaml
+releasenotes/notes/prevent-unauthorized-errors-ebb9cf2236595cd0.yaml
+releasenotes/notes/queens-relnote-5fa2d009d9a9e458.yaml
+releasenotes/notes/rbd-trash-snapshots-158a39da4248fb0c.yaml
+releasenotes/notes/release-1.0.0-7ab43e91523eb3c8.yaml
+releasenotes/notes/release-1.0.1-098b1487ac8cc9a1.yaml
+releasenotes/notes/release-1.2.0-8d239f01cd8ff0bf.yaml
+releasenotes/notes/releasenote-0.17.0-efee3f557ea2096a.yaml
+releasenotes/notes/remove-cinder-experimental-fbf9dea32c84dc9b.yaml
+releasenotes/notes/remove-gridfs-driver-09286e27613b4353.yaml
+releasenotes/notes/remove-py38-ad3b92513d4381e3.yaml
+releasenotes/notes/remove-py39-0f971df8daf45202.yaml
+releasenotes/notes/remove-s3-driver-f432afa1f53ecdf8.yaml
+releasenotes/notes/remove-store-cap-update-min-interval-21fea4173ed4a09b.yaml
+releasenotes/notes/rethinking-filesystem-access-5ab872fd0c0d27db.yaml
+releasenotes/notes/rocky-bugfixes-adefa8f47db16a2d.yaml
+releasenotes/notes/set-documented-default-directory-for-filesystem-9b417a29416d3a94.yaml
+releasenotes/notes/sorted-drivers-for-configs-a905f07d3bf9c973.yaml
+releasenotes/notes/start-using-reno-73ef709807e37b74.yaml
+releasenotes/notes/support-cinder-multiple-stores-6cc8489f8f4f8ff3.yaml
+releasenotes/notes/support-cinder-upload-c85849d9c88bbd7e.yaml
+releasenotes/notes/support-cinder-user-domain-420c76053dd50534.yaml
+releasenotes/notes/support-s3-driver-a4158f9fa35931d5.yaml
+releasenotes/notes/swift-remove-auth-version-v1-and-v2-d2372f9feea42f2c.yaml
+releasenotes/notes/update-stein-deprecations-3c2f6ffeab22b558.yaml
+releasenotes/notes/victoria-milestone-1-c1f9de5b90e8c326.yaml
+releasenotes/notes/vmware-store-requests-369485d2cfdb6175.yaml
+releasenotes/notes/volume-type-validation-check-011a400d7fb3b307.yaml
+releasenotes/notes/wallaby-final-release-00f0f851ff7d93ab.yaml
+releasenotes/notes/xena-final-release-3c6e19dfba43b40d.yaml
+releasenotes/source/2023.1.rst
+releasenotes/source/2023.2.rst
+releasenotes/source/2024.1.rst
+releasenotes/source/2024.2.rst
+releasenotes/source/2025.1.rst
+releasenotes/source/conf.py
+releasenotes/source/index.rst
+releasenotes/source/liberty.rst
+releasenotes/source/mitaka.rst
+releasenotes/source/newton.rst
+releasenotes/source/ocata.rst
+releasenotes/source/pike.rst
+releasenotes/source/queens.rst
+releasenotes/source/rocky.rst
+releasenotes/source/stein.rst
+releasenotes/source/train.rst
+releasenotes/source/unreleased.rst
+releasenotes/source/ussuri.rst
+releasenotes/source/victoria.rst
+releasenotes/source/wallaby.rst
+releasenotes/source/xena.rst
+releasenotes/source/yoga.rst
+releasenotes/source/zed.rst
+releasenotes/source/_static/.placeholder
+releasenotes/source/_templates/.placeholder
+releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po
+releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
+releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po
+tools/with_venv.sh
\ No newline at end of file
diff -pruN 4.9.1-2/glance_store.egg-info/dependency_links.txt 5.0.0-0ubuntu2/glance_store.egg-info/dependency_links.txt
--- 4.9.1-2/glance_store.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/dependency_links.txt	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 4.9.1-2/glance_store.egg-info/entry_points.txt 5.0.0-0ubuntu2/glance_store.egg-info/entry_points.txt
--- 4.9.1-2/glance_store.egg-info/entry_points.txt	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/entry_points.txt	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,23 @@
+[console_scripts]
+glance-rootwrap = oslo_rootwrap.cmd:main
+
+[glance_store.drivers]
+cinder = glance_store._drivers.cinder:Store
+file = glance_store._drivers.filesystem:Store
+glance.store.cinder.Store = glance_store._drivers.cinder:Store
+glance.store.filesystem.Store = glance_store._drivers.filesystem:Store
+glance.store.http.Store = glance_store._drivers.http:Store
+glance.store.rbd.Store = glance_store._drivers.rbd:Store
+glance.store.s3.Store = glance_store._drivers.s3:Store
+glance.store.swift.Store = glance_store._drivers.swift:Store
+glance.store.vmware_datastore.Store = glance_store._drivers.vmware_datastore:Store
+http = glance_store._drivers.http:Store
+no_conf = glance_store.tests.fakes:UnconfigurableStore
+rbd = glance_store._drivers.rbd:Store
+s3 = glance_store._drivers.s3:Store
+swift = glance_store._drivers.swift:Store
+vmware = glance_store._drivers.vmware_datastore:Store
+
+[oslo.config.opts]
+glance.multi_store = glance_store.multi_backend:_list_config_opts
+glance.store = glance_store.backend:_list_opts
diff -pruN 4.9.1-2/glance_store.egg-info/not-zip-safe 5.0.0-0ubuntu2/glance_store.egg-info/not-zip-safe
--- 4.9.1-2/glance_store.egg-info/not-zip-safe	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/not-zip-safe	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 4.9.1-2/glance_store.egg-info/pbr.json 5.0.0-0ubuntu2/glance_store.egg-info/pbr.json
--- 4.9.1-2/glance_store.egg-info/pbr.json	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/pbr.json	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1 @@
+{"git_version": "9a5271c", "is_release": true}
\ No newline at end of file
diff -pruN 4.9.1-2/glance_store.egg-info/requires.txt 5.0.0-0ubuntu2/glance_store.egg-info/requires.txt
--- 4.9.1-2/glance_store.egg-info/requires.txt	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/requires.txt	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1,48 @@
+oslo.config>=5.2.0
+oslo.i18n>=3.15.3
+oslo.serialization!=2.19.1,>=2.18.0
+oslo.utils>=4.7.0
+oslo.concurrency>=3.26.0
+stevedore>=1.20.0
+eventlet!=0.18.3,!=0.20.1,>=0.18.2
+jsonschema>=3.2.0
+keystoneauth1>=3.4.0
+python-keystoneclient>=3.8.0
+requests>=2.14.2
+
+[cinder]
+python-cinderclient>=4.1.0
+os-brick>=6.3.0
+oslo.rootwrap>=5.8.0
+oslo.privsep>=1.23.0
+
+[s3]
+boto3>=1.9.199
+
+[swift]
+python-swiftclient>=3.2.0
+
+[test]
+hacking<6.2.0,>=6.1.0
+doc8>=0.6.0
+coverage!=4.4,>=4.0
+ddt>=1.4.4
+fixtures>=3.0.0
+requests-mock>=1.2.0
+retrying>=1.3.3
+stestr>=2.0.0
+testscenarios>=0.4
+testtools>=2.2.0
+oslotest>=3.2.0
+openstacksdk>=0.10.0
+boto3>=1.9.199
+oslo.vmware>=3.6.0
+httplib2>=0.9.1
+python-swiftclient>=3.2.0
+python-cinderclient>=4.1.0
+os-brick>=2.6.0
+oslo.rootwrap>=5.8.0
+oslo.privsep>=1.23.0
+
+[vmware]
+oslo.vmware>=3.6.0
diff -pruN 4.9.1-2/glance_store.egg-info/top_level.txt 5.0.0-0ubuntu2/glance_store.egg-info/top_level.txt
--- 4.9.1-2/glance_store.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/glance_store.egg-info/top_level.txt	2025-07-10 09:13:41.000000000 +0000
@@ -0,0 +1 @@
+glance_store
diff -pruN 4.9.1-2/releasenotes/notes/add-backend-defaults-group-4c320deac0f234ee.yaml 5.0.0-0ubuntu2/releasenotes/notes/add-backend-defaults-group-4c320deac0f234ee.yaml
--- 4.9.1-2/releasenotes/notes/add-backend-defaults-group-4c320deac0f234ee.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/notes/add-backend-defaults-group-4c320deac0f234ee.yaml	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Added a new ``[backend_defaults]`` section in the glance
+    configuration file.
+    Now operators can add common configuration options in the
+    ``[backend_defaults]`` section which will act as a fallback
+    mechanism for a configuration option not defined in the
+    main backend group.
diff -pruN 4.9.1-2/releasenotes/notes/deprecate-filesystem_store_datadirs-40c54304cae4e11a.yaml 5.0.0-0ubuntu2/releasenotes/notes/deprecate-filesystem_store_datadirs-40c54304cae4e11a.yaml
--- 4.9.1-2/releasenotes/notes/deprecate-filesystem_store_datadirs-40c54304cae4e11a.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/notes/deprecate-filesystem_store_datadirs-40c54304cae4e11a.yaml	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,10 @@
+---
+deprecations:
+  - |
+    The ``filesystem_store_datadirs`` option has been deprecated in this
+    release and is subject to removal at the beginning of the `H` (2026.2)
+    development cycle, following the `OpenStack standard deprecation policy
+    <https://governance.openstack.org/reference/tags/assert_follows-standard-deprecation.html>`_.
+
+    Users should configure multiple filesystem stores instead of using this
+    option.
diff -pruN 4.9.1-2/releasenotes/notes/remove-py39-0f971df8daf45202.yaml 5.0.0-0ubuntu2/releasenotes/notes/remove-py39-0f971df8daf45202.yaml
--- 4.9.1-2/releasenotes/notes/remove-py39-0f971df8daf45202.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/notes/remove-py39-0f971df8daf45202.yaml	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - |
+    Support for Pyton 3.9 has been removed. Now Python 3.10 is the minimum
+    version supported.
diff -pruN 4.9.1-2/releasenotes/notes/swift-remove-auth-version-v1-and-v2-d2372f9feea42f2c.yaml 5.0.0-0ubuntu2/releasenotes/notes/swift-remove-auth-version-v1-and-v2-d2372f9feea42f2c.yaml
--- 4.9.1-2/releasenotes/notes/swift-remove-auth-version-v1-and-v2-d2372f9feea42f2c.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/notes/swift-remove-auth-version-v1-and-v2-d2372f9feea42f2c.yaml	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,10 @@
+---
+upgrade:
+  - |
+    Swift store driver no longer supports auth_version less than 3. Now
+    the driver uses identity v3 API by default.
+
+deprecations:
+  - |
+    The ``auth_version`` option of the swift back-end configrations file
+    has been deprecated and will be removed in a future release.
diff -pruN 4.9.1-2/releasenotes/source/2025.1.rst 5.0.0-0ubuntu2/releasenotes/source/2025.1.rst
--- 4.9.1-2/releasenotes/source/2025.1.rst	1970-01-01 00:00:00.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/source/2025.1.rst	2025-07-10 09:13:16.000000000 +0000
@@ -0,0 +1,6 @@
+===========================
+2025.1 Series Release Notes
+===========================
+
+.. release-notes::
+   :branch: stable/2025.1
diff -pruN 4.9.1-2/releasenotes/source/index.rst 5.0.0-0ubuntu2/releasenotes/source/index.rst
--- 4.9.1-2/releasenotes/source/index.rst	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/source/index.rst	2025-07-10 09:13:16.000000000 +0000
@@ -6,6 +6,7 @@
    :maxdepth: 1
 
    unreleased
+   2025.1
    2024.2
    2024.1
    2023.2
diff -pruN 4.9.1-2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po 5.0.0-0ubuntu2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
--- 4.9.1-2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po	2025-07-10 09:13:16.000000000 +0000
@@ -7,15 +7,16 @@
 # Andi Chandler <andi@gowling.com>, 2022. #zanata
 # Andi Chandler <andi@gowling.com>, 2023. #zanata
 # Andi Chandler <andi@gowling.com>, 2024. #zanata
+# Andi Chandler <andi@gowling.com>, 2025. #zanata
 msgid ""
 msgstr ""
 "Project-Id-Version: Glance_store Release Notes\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-12-12 15:41+0000\n"
+"POT-Creation-Date: 2025-02-06 17:30+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2024-12-16 04:58+0000\n"
+"PO-Revision-Date: 2025-02-07 12:09+0000\n"
 "Last-Translator: Andi Chandler <andi@gowling.com>\n"
 "Language-Team: English (United Kingdom)\n"
 "Language: en_GB\n"
@@ -162,12 +163,12 @@ msgstr "4.7.0-4"
 msgid "4.8.0"
 msgstr "4.8.0"
 
-msgid "4.8.1-12"
-msgstr "4.8.1-12"
-
 msgid "4.8.1-4"
 msgstr "4.8.1-4"
 
+msgid "4.9.0"
+msgstr "4.9.0"
+
 msgid ""
 "A `BufferedReader`_ has been added to the Swift store driver in order to "
 "enable better recovery from errors during uploads of large image files.  "
diff -pruN 4.9.1-2/setup.cfg 5.0.0-0ubuntu2/setup.cfg
--- 4.9.1-2/setup.cfg	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/setup.cfg	2025-07-10 09:13:41.907623800 +0000
@@ -1,76 +1,75 @@
 [metadata]
 name = glance_store
 summary = OpenStack Image Service Store Library
-description_file =
-    README.rst
+description_file = 
+	README.rst
 author = OpenStack
 author_email = openstack-discuss@lists.openstack.org
 home_page = https://docs.openstack.org/glance_store/latest/
-python_requires = >=3.9
-classifier =
-    Development Status :: 5 - Production/Stable
-    Environment :: OpenStack
-    Intended Audience :: Developers
-    Intended Audience :: Information Technology
-    License :: OSI Approved :: Apache Software License
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python
-    Programming Language :: Python :: Implementation :: CPython
-    Programming Language :: Python :: 3 :: Only
-    Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.9
-    Programming Language :: Python :: 3.10
-    Programming Language :: Python :: 3.11
-    Programming Language :: Python :: 3.12
+python_requires = >=3.10
+classifier = 
+	Development Status :: 5 - Production/Stable
+	Environment :: OpenStack
+	Intended Audience :: Developers
+	Intended Audience :: Information Technology
+	License :: OSI Approved :: Apache Software License
+	Operating System :: POSIX :: Linux
+	Programming Language :: Python
+	Programming Language :: Python :: Implementation :: CPython
+	Programming Language :: Python :: 3 :: Only
+	Programming Language :: Python :: 3
+	Programming Language :: Python :: 3.10
+	Programming Language :: Python :: 3.11
+	Programming Language :: Python :: 3.12
 
 [files]
-packages =
-    glance_store
-data_files =
-    etc/glance =
-        etc/glance/rootwrap.conf
-    etc/glance/rootwrap.d =
-        etc/glance/rootwrap.d/glance_cinder_store.filters
+packages = 
+	glance_store
+data_files = 
+	etc/glance =
+	etc/glance/rootwrap.conf
+	etc/glance/rootwrap.d =
+	etc/glance/rootwrap.d/glance_cinder_store.filters
 
 [entry_points]
-glance_store.drivers =
-    file = glance_store._drivers.filesystem:Store
-    http = glance_store._drivers.http:Store
-    swift = glance_store._drivers.swift:Store
-    rbd = glance_store._drivers.rbd:Store
-    cinder = glance_store._drivers.cinder:Store
-    vmware = glance_store._drivers.vmware_datastore:Store
-    s3 = glance_store._drivers.s3:Store
-
-    # TESTS ONLY
-    no_conf = glance_store.tests.fakes:UnconfigurableStore
-
-    # Backwards compatibility
-    glance.store.filesystem.Store = glance_store._drivers.filesystem:Store
-    glance.store.http.Store = glance_store._drivers.http:Store
-    glance.store.swift.Store = glance_store._drivers.swift:Store
-    glance.store.rbd.Store = glance_store._drivers.rbd:Store
-    glance.store.cinder.Store = glance_store._drivers.cinder:Store
-    glance.store.vmware_datastore.Store = glance_store._drivers.vmware_datastore:Store
-    glance.store.s3.Store = glance_store._drivers.s3:Store
-
-oslo.config.opts =
-    glance.store = glance_store.backend:_list_opts
-    glance.multi_store = glance_store.multi_backend:_list_config_opts
-
-console_scripts =
-    glance-rootwrap = oslo_rootwrap.cmd:main
+glance_store.drivers = 
+	file = glance_store._drivers.filesystem:Store
+	http = glance_store._drivers.http:Store
+	swift = glance_store._drivers.swift:Store
+	rbd = glance_store._drivers.rbd:Store
+	cinder = glance_store._drivers.cinder:Store
+	vmware = glance_store._drivers.vmware_datastore:Store
+	s3 = glance_store._drivers.s3:Store
+	
+	no_conf = glance_store.tests.fakes:UnconfigurableStore
+	
+	glance.store.filesystem.Store = glance_store._drivers.filesystem:Store
+	glance.store.http.Store = glance_store._drivers.http:Store
+	glance.store.swift.Store = glance_store._drivers.swift:Store
+	glance.store.rbd.Store = glance_store._drivers.rbd:Store
+	glance.store.cinder.Store = glance_store._drivers.cinder:Store
+	glance.store.vmware_datastore.Store = glance_store._drivers.vmware_datastore:Store
+	glance.store.s3.Store = glance_store._drivers.s3:Store
+oslo.config.opts = 
+	glance.store = glance_store.backend:_list_opts
+	glance.multi_store = glance_store.multi_backend:_list_config_opts
+console_scripts = 
+	glance-rootwrap = oslo_rootwrap.cmd:main
 
 [extras]
-# Dependencies for each of the optional stores
-vmware =
-  oslo.vmware>=3.6.0 # Apache-2.0
-swift =
-  python-swiftclient>=3.2.0 # Apache-2.0
-cinder =
-  python-cinderclient>=4.1.0 # Apache-2.0
-  os-brick>=6.3.0 # Apache-2.0
-  oslo.rootwrap>=5.8.0 # Apache-2.0
-  oslo.privsep>=1.23.0 # Apache-2.0
-s3 =
-  boto3>=1.9.199 # Apache-2.0
+vmware = 
+	oslo.vmware>=3.6.0 # Apache-2.0
+swift = 
+	python-swiftclient>=3.2.0 # Apache-2.0
+cinder = 
+	python-cinderclient>=4.1.0 # Apache-2.0
+	os-brick>=6.3.0 # Apache-2.0
+	oslo.rootwrap>=5.8.0 # Apache-2.0
+	oslo.privsep>=1.23.0 # Apache-2.0
+s3 = 
+	boto3>=1.9.199 # Apache-2.0
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff -pruN 4.9.1-2/test-requirements.txt 5.0.0-0ubuntu2/test-requirements.txt
--- 4.9.1-2/test-requirements.txt	2024-12-17 03:53:21.000000000 +0000
+++ 5.0.0-0ubuntu2/test-requirements.txt	2025-07-10 09:13:16.000000000 +0000
@@ -9,7 +9,6 @@ doc8>=0.6.0 # Apache-2.0
 coverage!=4.4,>=4.0 # Apache-2.0
 ddt>=1.4.4 # MIT
 fixtures>=3.0.0 # Apache-2.0/BSD
-python-subunit>=1.0.0 # Apache-2.0/BSD
 requests-mock>=1.2.0 # Apache-2.0
 retrying>=1.3.3
 stestr>=2.0.0 # Apache-2.0
@@ -17,6 +16,9 @@ testscenarios>=0.4 # Apache-2.0/BSD
 testtools>=2.2.0 # MIT
 oslotest>=3.2.0 # Apache-2.0
 
+# Functional testing
+openstacksdk>=0.10.0 # Apache-2.0
+
 # Dependencies for each of the optional stores
 boto3>=1.9.199 # Apache-2.0
 oslo.vmware>=3.6.0 # Apache-2.0
