)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"369c02a70b8b1da202b5cdc5da70c8cbe160e81a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"7254781c_4974010f","updated":"2026-05-24 07:00:25.000000000","message":"recheck","commit_id":"0aea42100c9fbbedb1c45a3cd2f034aabf17c788"},{"author":{"_account_id":28691,"name":"Bo Tran","email":"ministry.96.nd@gmail.com","username":"ministry"},"change_message_id":"ab366ac1b0a645cfb0e8ec0d4e008166c27af14d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"364f9d82_7d1998bb","updated":"2026-05-25 09:42:14.000000000","message":"can i push support redis support path before this path? because, i think redis should be based for your path.\n\nanw, if i can\u0027t, i think you should review about backup for keydb/ valkey again? whether we need do snapshot before snapshot?","commit_id":"26f182f09dd22401bd04886da8de789278198eab"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"226dde952cab04bae06e2874e4eb454c9a7e2335","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"0d171c70_1ca369bd","in_reply_to":"364f9d82_7d1998bb","updated":"2026-05-25 10:16:37.000000000","message":"Hello, Bo! Nice to hear from you.\n\nUnfortunately, we can\u0027t support vanilla Redis anymore due to licensing issues.\nSo the only option is to use forks: Valkey - looks more like a vanilla Redis 7.2.4, and KeyDB - focused on performance and multi-threading.\n\nActually, with the provided code, it\u0027s very easy to implement a \"Redis\" datastore using RedisCommon as a base class, and sell \"Redis\" DBaaS, if you can overcome licensing issues.\n\nI can\u0027t clearly get a point about backup and snapshots. Is there something wrong with the current implementation?","commit_id":"26f182f09dd22401bd04886da8de789278198eab"},{"author":{"_account_id":28691,"name":"Bo Tran","email":"ministry.96.nd@gmail.com","username":"ministry"},"change_message_id":"d4ffeef94cfa0471ddcfda1b7083d56a2aa665db","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"b09c787a_91e1dc3f","updated":"2026-05-26 06:55:15.000000000","message":"I think you should do save to disk before snapshot.","commit_id":"a2cf0f7133235faa5007390b3553c37dda97f7af"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"04538ba29be3c472d0a727311a2409cf6aabea5a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"f9468560_a1f111ba","updated":"2026-05-25 14:35:35.000000000","message":"recheck","commit_id":"a2cf0f7133235faa5007390b3553c37dda97f7af"},{"author":{"_account_id":28691,"name":"Bo Tran","email":"ministry.96.nd@gmail.com","username":"ministry"},"change_message_id":"181a0618d0439a0e17239bd45a347d9e63e4f3ec","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"adec4469_78af0420","in_reply_to":"00a3dcc1_e6d1256d","updated":"2026-05-27 01:38:23.000000000","message":"ah, ok. my wrong.","commit_id":"a2cf0f7133235faa5007390b3553c37dda97f7af"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"d625272c400c2369096e135b96a23fc5f4df3c80","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"00a3dcc1_e6d1256d","in_reply_to":"b09c787a_91e1dc3f","updated":"2026-05-26 09:01:02.000000000","message":"Ah, yes, right. We do it for [cinder backups](https://review.opendev.org/c/openstack/trove/+/989856/10/trove/guestagent/datastore/redis_common/manager.py#188), and for [swift backups](https://review.opendev.org/c/openstack/trove/+/989856/10/trove/guestagent/datastore/redis_common/manager.py#120) too.\nReplication snapshots utilize this code too.\nOr maybe I\u0027m missing something?","commit_id":"a2cf0f7133235faa5007390b3553c37dda97f7af"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"46f0db4273b8eec6a1e37f1a0c39b7435546509e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":21,"id":"93becb8c_ec038053","updated":"2026-06-05 12:58:51.000000000","message":"recheck","commit_id":"a8ee1b9b415536d9c3a75676bf1fd8837d53239b"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"7fba8a0bbab94a3b25563eb79769c6e84bbff624","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":21,"id":"ddd072da_8ac90f13","updated":"2026-06-05 08:34:55.000000000","message":"recheck","commit_id":"a8ee1b9b415536d9c3a75676bf1fd8837d53239b"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"67f3a92b0a03a0cb181a7fc407280fb8765cdf5c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":40,"id":"16458110_a610543f","updated":"2026-06-09 08:49:11.000000000","message":"recheck","commit_id":"64fcd106b2072c99c0ee2ca52ea24e42d8002132"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"53cb2241f6e6d2fd54e7e0c467172ce922d2ca24","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":41,"id":"1bddb454_9c2b77e8","updated":"2026-06-26 08:37:30.000000000","message":"recheck","commit_id":"01524785ca5e9b0e457009f21e84a83f927f5317"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"3fdfa94e2955b9a43125b180b1c1cda7a2da66a1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":47,"id":"fda7c688_ceb8cb52","updated":"2026-09-22 13:57:40.000000000","message":"recheck","commit_id":"e062a93286384ef7f1f1fcdb45d8aebdeb5cf376"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"2409b9abca8e9813b9ed257b2fb4c160af058010","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":48,"id":"7cf70be3_e0ecfcbb","updated":"2026-09-23 03:22:35.000000000","message":"Thank you, LGTM!","commit_id":"d51f47106d6bd3c18c1321642c86d5741420714f"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"58063ffe5753853914197c7f0ad8e13ef379264b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":49,"id":"9edb8b7a_7afef965","updated":"2026-09-28 07:16:43.000000000","message":"LGTM","commit_id":"af90496ae363f40d8cb606836220d9baa67671cc"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"9d7c1750720dfe955d5bbfe59629d71c5bc662f8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":50,"id":"a3184ac9_06720ebf","updated":"2026-10-02 03:52:01.000000000","message":"Hello guys!\n\nThis MR has been open in Gerrit for more than six months and has been extensively tested in our cloud. It has also received a code review from my colleague and passed an additional AI-assisted review. The MR is large (+3K lines), but further development of several upcoming features - including pre-attach configuration validation, special-character support, exporters, and replication unsync status - requires implementing and testing those features for KeyDB/Valkey as well. Keeping the base KeyDB/Valkey support unmerged makes this work significantly harder to develop and validate. Given the currently very low activity from the core reviewer team, I plan to merge this MR on Monday, October 5, unless any core reviewer raises an objection or does a review before then.","commit_id":"217db27fd133aa5a49ce519d59507b6c53120043"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b31aeeccbf268bc44e3470893adc53d82323cc6c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":50,"id":"5e4f4b60_dbdc0810","updated":"2026-10-02 09:30:53.000000000","message":"LGTM!","commit_id":"217db27fd133aa5a49ce519d59507b6c53120043"},{"author":{"_account_id":37598,"name":"Ivan Anfimov","display_name":"Ivan Anfimov","email":"lazekteam@gmail.com","username":"anfimovir"},"change_message_id":"a8027f3d24073bffeef5253beb4338f52251f0bd","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":50,"id":"0bc7b62f_6acf0ff3","updated":"2026-10-02 04:01:33.000000000","message":"LGTM, time to merge it.","commit_id":"217db27fd133aa5a49ce519d59507b6c53120043"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"1ea58028265a727f141e7655bfd1ef579e508b08","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":50,"id":"0b6bebab_94d36a4b","updated":"2026-10-01 12:09:24.000000000","message":"recheck","commit_id":"217db27fd133aa5a49ce519d59507b6c53120043"}],"trove/guestagent/datastore/redis_common/manager.py":[{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":true,"context_lines":[{"line_number":159,"context_line":"        # No transactions support in Redis"},{"line_number":160,"context_line":"        pass"},{"line_number":161,"context_line":""},{"line_number":162,"context_line":"    def wait_for_txn(self, context):"},{"line_number":163,"context_line":"        # No transactions support in Redis"},{"line_number":164,"context_line":"        pass"},{"line_number":165,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"79ea80b1_5c758d44","line":162,"updated":"2026-09-11 09:13:53.000000000","message":"Isn\u0027t the `txn` argument missing? I mean, the base manager defines this as `wait_for_txn(self, context, txn)`, and the promotion flow passes `latest_txn_id`, so wouldn\u0027t it fail with a `TypeError`?","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":159,"context_line":"        # No transactions support in Redis"},{"line_number":160,"context_line":"        pass"},{"line_number":161,"context_line":""},{"line_number":162,"context_line":"    def wait_for_txn(self, context):"},{"line_number":163,"context_line":"        # No transactions support in Redis"},{"line_number":164,"context_line":"        pass"},{"line_number":165,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"d53eee85_3eb6d802","line":162,"in_reply_to":"79ea80b1_5c758d44","updated":"2026-09-16 15:01:32.000000000","message":"Done","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"}],"trove/guestagent/datastore/redis_common/service.py":[{"author":{"_account_id":5733,"name":"Kieran Spear","email":"kispear@gmail.com","username":"kspear"},"change_message_id":"3885ec1a1d230adb28bdbc9b91189285f3d65808","unresolved":true,"context_lines":[{"line_number":366,"context_line":"        self._password \u003d password"},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"    def connect(self):"},{"line_number":369,"context_line":"        self._connection \u003d Valkey("},{"line_number":370,"context_line":"            unix_socket_path\u003dself._unix_socket_path,"},{"line_number":371,"context_line":"            username\u003dself._username,"},{"line_number":372,"context_line":"            password\u003dself._password)"}],"source_content_type":"text/x-python","patch_set":42,"id":"5a073b28_33e427af","line":369,"updated":"2026-08-10 06:45:11.000000000","message":"Does this need to be overridden per-datastore?","commit_id":"f3d2eb4168f437c02bca8de83a521238d75a6ee7"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"4c7c4ba0db22c898f0250a05b4db68933f93f1e4","unresolved":true,"context_lines":[{"line_number":366,"context_line":"        self._password \u003d password"},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"    def connect(self):"},{"line_number":369,"context_line":"        self._connection \u003d Valkey("},{"line_number":370,"context_line":"            unix_socket_path\u003dself._unix_socket_path,"},{"line_number":371,"context_line":"            username\u003dself._username,"},{"line_number":372,"context_line":"            password\u003dself._password)"}],"source_content_type":"text/x-python","patch_set":42,"id":"8c56de9c_ac2d7998","line":369,"in_reply_to":"5a073b28_33e427af","updated":"2026-08-10 14:03:25.000000000","message":"I can\u0027t exactly get the point.\nThis is a common class, used as a base class for KeyDB and Valkey. So this code works for both of them.\nBut we use the same Valkey Python library here, as the Redis protocol is compatible and it\u0027s already in global Openstack [upper-constraints](https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt) list.","commit_id":"f3d2eb4168f437c02bca8de83a521238d75a6ee7"},{"author":{"_account_id":5733,"name":"Kieran Spear","email":"kispear@gmail.com","username":"kspear"},"change_message_id":"810d07e96ad7182c11902f3113b48a261fb50534","unresolved":false,"context_lines":[{"line_number":366,"context_line":"        self._password \u003d password"},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"    def connect(self):"},{"line_number":369,"context_line":"        self._connection \u003d Valkey("},{"line_number":370,"context_line":"            unix_socket_path\u003dself._unix_socket_path,"},{"line_number":371,"context_line":"            username\u003dself._username,"},{"line_number":372,"context_line":"            password\u003dself._password)"}],"source_content_type":"text/x-python","patch_set":42,"id":"fa9b174b_706748df","line":369,"in_reply_to":"8c56de9c_ac2d7998","updated":"2026-08-11 00:10:55.000000000","message":"You\u0027re right, I got confused and thought `Valkey` was a local class here.","commit_id":"f3d2eb4168f437c02bca8de83a521238d75a6ee7"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":false,"context_lines":[{"line_number":507,"context_line":"        raise exception.TroveError(\"Creating databases is not supported\")"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    def create_database(self, *args, **kwargs):"},{"line_number":510,"context_line":"        raise exception.TroveError(\"Create database is not supported\")"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"    def delete_database(self, database):"},{"line_number":513,"context_line":"        raise exception.TroveError(\"Deleting database is not supported\")"}],"source_content_type":"text/x-python","patch_set":44,"id":"97af5d65_538844a7","line":510,"updated":"2026-09-11 09:13:53.000000000","message":"Just curious, why the infinitive here and the gerund three lines above?","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":507,"context_line":"        raise exception.TroveError(\"Creating databases is not supported\")"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    def create_database(self, *args, **kwargs):"},{"line_number":510,"context_line":"        raise exception.TroveError(\"Create database is not supported\")"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"    def delete_database(self, database):"},{"line_number":513,"context_line":"        raise exception.TroveError(\"Deleting database is not supported\")"}],"source_content_type":"text/x-python","patch_set":44,"id":"2f3ce746_735a7a8e","line":510,"in_reply_to":"97af5d65_538844a7","updated":"2026-09-16 15:01:32.000000000","message":"Probably some copy-paste issue 😄","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":true,"context_lines":[{"line_number":522,"context_line":"            limit\u003dlimit, marker\u003dmarker, include_marker\u003dinclude_marker)"},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"    def create_users(self, users):"},{"line_number":525,"context_line":"        LOG.info(f\"Calling create_users {users}\")"},{"line_number":526,"context_line":"        for user in users:"},{"line_number":527,"context_line":"            self.create_non_root_user("},{"line_number":528,"context_line":"                models.RedisCommonUser.deserialize(user, False)"}],"source_content_type":"text/x-python","patch_set":44,"id":"164321ef_01cf2f79","line":525,"updated":"2026-09-11 09:13:53.000000000","message":"Oops, looks like this logs the serialized users, including their passwords. And the `kwargs` log below may expose the passwords, too.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":522,"context_line":"            limit\u003dlimit, marker\u003dmarker, include_marker\u003dinclude_marker)"},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"    def create_users(self, users):"},{"line_number":525,"context_line":"        LOG.info(f\"Calling create_users {users}\")"},{"line_number":526,"context_line":"        for user in users:"},{"line_number":527,"context_line":"            self.create_non_root_user("},{"line_number":528,"context_line":"                models.RedisCommonUser.deserialize(user, False)"}],"source_content_type":"text/x-python","patch_set":44,"id":"f8ff01b8_6d2b6036","line":525,"in_reply_to":"164321ef_01cf2f79","updated":"2026-09-16 15:01:32.000000000","message":"Oops, forgot to cleanup after some debugging 😅","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":true,"context_lines":[{"line_number":524,"context_line":"    def create_users(self, users):"},{"line_number":525,"context_line":"        LOG.info(f\"Calling create_users {users}\")"},{"line_number":526,"context_line":"        for user in users:"},{"line_number":527,"context_line":"            self.create_non_root_user("},{"line_number":528,"context_line":"                models.RedisCommonUser.deserialize(user, False)"},{"line_number":529,"context_line":"            )"},{"line_number":530,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"7747a344_2213a21d","line":527,"updated":"2026-09-11 09:13:53.000000000","message":"IMO, the internal ACL users should be explicitly protected in all user mutation paths. `default`, `osadmin`, and `replication` are hidden from `list_users()`, so the duplicate check cannot see them.\n\nWith the default API configuration, reserved-user validation falls back to the MySQL list (`os_admin`, `root`), which does not include these names, so a create request for `osadmin` may reach `ACL SETUSER`. For an existing user, the new rules are applied in addition to the existing ones, and `osadmin` would retain `+@all` while acquiring a password known to the tenant.\n\nCould we reject these names explicitly on create, delete, rename, and password change?","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":524,"context_line":"    def create_users(self, users):"},{"line_number":525,"context_line":"        LOG.info(f\"Calling create_users {users}\")"},{"line_number":526,"context_line":"        for user in users:"},{"line_number":527,"context_line":"            self.create_non_root_user("},{"line_number":528,"context_line":"                models.RedisCommonUser.deserialize(user, False)"},{"line_number":529,"context_line":"            )"},{"line_number":530,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"362dd7e9_ccfd26da","line":527,"in_reply_to":"7747a344_2213a21d","updated":"2026-09-16 15:01:32.000000000","message":"Done, nice catch!","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"460a0ed6820652413f75fa97c087aa86bdddbbc7","unresolved":true,"context_lines":[{"line_number":552,"context_line":"                kwargs[\"categories\"] \u003d list("},{"line_number":553,"context_line":"                    dict.fromkeys(kwargs[\"categories\"]))"},{"line_number":554,"context_line":""},{"line_number":555,"context_line":"        LOG.info(\"args on user create: %s\", kwargs)"},{"line_number":556,"context_line":"        self.connection.acl_setuser(user.name,"},{"line_number":557,"context_line":"                                    enabled\u003denabled, **kwargs)"},{"line_number":558,"context_line":"        self.connection.acl_save()"}],"source_content_type":"text/x-python","patch_set":44,"id":"be898f60_c6a9ba7c","line":555,"updated":"2026-09-17 05:55:12.000000000","message":"`kwargs[\"passwords\"]` contains the user\u0027s password (line 536), so this log will exposes it, too.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"6124b078c6256c594b94f37fc63524834e1f58cb","unresolved":false,"context_lines":[{"line_number":552,"context_line":"                kwargs[\"categories\"] \u003d list("},{"line_number":553,"context_line":"                    dict.fromkeys(kwargs[\"categories\"]))"},{"line_number":554,"context_line":""},{"line_number":555,"context_line":"        LOG.info(\"args on user create: %s\", kwargs)"},{"line_number":556,"context_line":"        self.connection.acl_setuser(user.name,"},{"line_number":557,"context_line":"                                    enabled\u003denabled, **kwargs)"},{"line_number":558,"context_line":"        self.connection.acl_save()"}],"source_content_type":"text/x-python","patch_set":44,"id":"4d6ac294_7915b6cd","line":555,"in_reply_to":"be898f60_c6a9ba7c","updated":"2026-09-22 14:03:02.000000000","message":"Done","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"460a0ed6820652413f75fa97c087aa86bdddbbc7","unresolved":true,"context_lines":[{"line_number":665,"context_line":"            new_name \u003d user_attrs.get(\u0027name\u0027)"},{"line_number":666,"context_line":"            if new_name in self.ignore_users:"},{"line_number":667,"context_line":"                raise exception.TroveError("},{"line_number":668,"context_line":"                    \"%s username is reserved\" % user.name)"},{"line_number":669,"context_line":"            LOG.debug("},{"line_number":670,"context_line":"                \"Name changed for user %s, new name: %s.\", username, new_name)"},{"line_number":671,"context_line":"            self.delete_user(user)"}],"source_content_type":"text/x-python","patch_set":46,"id":"591a4327_6d6d4376","line":668,"updated":"2026-09-17 05:55:12.000000000","message":"A tiny typo: `new_name`","commit_id":"239454cb065e479e94f2bb35aada675a3e19c824"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"6124b078c6256c594b94f37fc63524834e1f58cb","unresolved":false,"context_lines":[{"line_number":665,"context_line":"            new_name \u003d user_attrs.get(\u0027name\u0027)"},{"line_number":666,"context_line":"            if new_name in self.ignore_users:"},{"line_number":667,"context_line":"                raise exception.TroveError("},{"line_number":668,"context_line":"                    \"%s username is reserved\" % user.name)"},{"line_number":669,"context_line":"            LOG.debug("},{"line_number":670,"context_line":"                \"Name changed for user %s, new name: %s.\", username, new_name)"},{"line_number":671,"context_line":"            self.delete_user(user)"}],"source_content_type":"text/x-python","patch_set":46,"id":"3bdfbc91_0662d343","line":668,"in_reply_to":"591a4327_6d6d4376","updated":"2026-09-22 14:03:02.000000000","message":"Done","commit_id":"239454cb065e479e94f2bb35aada675a3e19c824"}],"trove/guestagent/strategies/replication/redis_base.py":[{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":26,"context_line":"CONF \u003d cfg.CONF"},{"line_number":27,"context_line":"MASTER_USER \u003d \u0027replication\u0027"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class RedisReplicationBase(base.Replication):"}],"source_content_type":"text/x-python","patch_set":44,"id":"e87cd768_82ff47e2","line":27,"updated":"2026-09-11 09:13:53.000000000","message":"This duplicates `redis_common.manager.REPLICATION_USER`. Could we move the shared Redis-family usernames to a small `redis_common/constants.py` module and import them from both places? This would keep a single source of truth without making the replication strategy depend on the datastore manager module.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":26,"context_line":"CONF \u003d cfg.CONF"},{"line_number":27,"context_line":"MASTER_USER \u003d \u0027replication\u0027"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class RedisReplicationBase(base.Replication):"}],"source_content_type":"text/x-python","patch_set":44,"id":"5db81e94_ceec10b5","line":27,"in_reply_to":"e87cd768_82ff47e2","updated":"2026-09-16 15:01:32.000000000","message":"Done. I think the new constants module is redundant; we can simply import the manager module here and use it as `manager.REPLICATION_USER`.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":true,"context_lines":[{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        \"\"\"Set up the replica server.\"\"\""},{"line_number":87,"context_line":"        host \u003d snapshot[\u0027master\u0027][\u0027host\u0027]"},{"line_number":88,"context_line":"        port \u003d snapshot[\u0027master\u0027][\u0027port\u0027][0]"},{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"}],"source_content_type":"text/x-python","patch_set":44,"id":"2716f813_09be15be","line":88,"updated":"2026-09-11 09:13:53.000000000","message":"Looks like `get_master_ref()` stores port as a scalar value but it\u0027s indexed again, and the same applies to the `slaveof()` call below. I believe this would fail with `TypeError`.\n\nMaybe both this assignment and the `slaveof()` call should use `snapshot[\u0027master\u0027][\u0027port\u0027]` directly?","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        \"\"\"Set up the replica server.\"\"\""},{"line_number":87,"context_line":"        host \u003d snapshot[\u0027master\u0027][\u0027host\u0027]"},{"line_number":88,"context_line":"        port \u003d snapshot[\u0027master\u0027][\u0027port\u0027][0]"},{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"}],"source_content_type":"text/x-python","patch_set":44,"id":"40c0eac4_95fb3df9","line":88,"in_reply_to":"2716f813_09be15be","updated":"2026-09-16 15:01:32.000000000","message":"Good observation.\n\nI dug deeper and found that the creation of such users is forbidden on the control-plane side, look [trove/extensions/common/service.py:333](https://opendev.org/openstack/trove/src/branch/master/trove/extensions/common/service.py#L331) and [trove/common/db/models.py:413](https://opendev.org/openstack/trove/src/branch/master/trove/common/db/models.py#L413). You should simply set a list of \"special\" users in `cfg.ignore_list` of your datastore configuration group. However, the implementation is broken. We should fix it first in a separate MR.\n\nSo placing an additional check here will duplicate that functionality. Also, it will not return any exceptions; it will silently ignore user creation and return a successful response, which may be confusing for the end user.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"460a0ed6820652413f75fa97c087aa86bdddbbc7","unresolved":false,"context_lines":[{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        \"\"\"Set up the replica server.\"\"\""},{"line_number":87,"context_line":"        host \u003d snapshot[\u0027master\u0027][\u0027host\u0027]"},{"line_number":88,"context_line":"        port \u003d snapshot[\u0027master\u0027][\u0027port\u0027][0]"},{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"}],"source_content_type":"text/x-python","patch_set":44,"id":"193ddde8_7e0b5350","line":88,"in_reply_to":"40c0eac4_95fb3df9","updated":"2026-09-17 05:55:12.000000000","message":"I get it now 😁 That\u0027s exactly [what I\u0027m working on](https://review.opendev.org/c/openstack/trove/+/1005855), I\u0027ll update the change based on your comments ASAP.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"b28a8e906195de8ea43406c329abf8339fe89910","unresolved":true,"context_lines":[{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"},{"line_number":92,"context_line":"            \u0027replicaof\u0027: [host, port],"},{"line_number":93,"context_line":"            \u0027masterauth\u0027: password,"},{"line_number":94,"context_line":"            \u0027masteruser\u0027: name,"},{"line_number":95,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":44,"id":"3ca9b425_21e41404","line":92,"updated":"2026-09-11 09:13:53.000000000","message":"I\u0027m trying to understand how TLS is enabled for the replication link. Valkey replicas use plaintext by default unless `tls-replication yes` is configured. Here, `replicaof` is applied without that option, while enforced and mtls modes disable the primary\u0027s plaintext port.\n\nAlso, in basic mode TLS listens on port 6380, but `get_master_ref()` advertises port 6379. Wouldn\u0027t replication remain down in enforced/mtls mode and continue over plaintext in basic mode?","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":36080,"name":"Erkin Mussurmankulov","display_name":"Eric","email":"erkin.mussurmankulov@ps.kz","username":"mongoose404","status":"PS Cloud services employee"},"change_message_id":"80a99aedcbaafd0d27f1cf1955edab4bf4052fb2","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"},{"line_number":92,"context_line":"            \u0027replicaof\u0027: [host, port],"},{"line_number":93,"context_line":"            \u0027masterauth\u0027: password,"},{"line_number":94,"context_line":"            \u0027masteruser\u0027: name,"},{"line_number":95,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":44,"id":"b919c910_9ba6e5c7","line":92,"in_reply_to":"3ca9b425_21e41404","updated":"2026-09-16 15:01:32.000000000","message":"This one was complicated and took me a while.\nI did write additional checks in SSL replication tests to ensure that replication actually works after all SSL manipulations, [here](https://review.opendev.org/c/openstack/trove-tempest-plugin/+/1005902).\nHowever, it may not run in Zuul because these tests run only with `CONF.database.run_full_tests \u003d True`. But it works in my local Devstack:\n\n```\n{0} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLKeyDB.test_ssl_replication_basic [142.053741s] ... ok\n{1} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLValkey.test_ssl_replication_basic [152.351812s] ... ok\n{0} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLKeyDB.test_ssl_replication_enforced [151.350715s] ... ok\n{1} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLValkey.test_ssl_replication_enforced [151.499581s] ... ok\n{0} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLKeyDB.test_ssl_replication_mtls [151.557871s] ... ok\n{1} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLValkey.test_ssl_replication_mtls [141.659169s] ... ok\n{0} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLKeyDB.test_ssl_replication_renew [227.671909s] ... ok\n{1} trove_tempest_plugin.tests.scenario.test_instance_ssl.TestInstanceSSLValkey.test_ssl_replication_renew [228.213688s] ... ok\n```\n\n\n\nJust adding `tls-replication yes` for `enforced` and `mtls` mode was enough to make it work correctly with these additional checks.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"},{"author":{"_account_id":39300,"name":"Olessya Khussainova","display_name":"Olessya Khussainova","email":"olessya.khussainova@ps.kz","username":"Cellofun"},"change_message_id":"460a0ed6820652413f75fa97c087aa86bdddbbc7","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        password \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027password\u0027]"},{"line_number":90,"context_line":"        name \u003d snapshot[\u0027replica_conf\u0027][\u0027replication_user\u0027][\u0027name\u0027]"},{"line_number":91,"context_line":"        conf \u003d {"},{"line_number":92,"context_line":"            \u0027replicaof\u0027: [host, port],"},{"line_number":93,"context_line":"            \u0027masterauth\u0027: password,"},{"line_number":94,"context_line":"            \u0027masteruser\u0027: name,"},{"line_number":95,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":44,"id":"2354a258_c363bf16","line":92,"in_reply_to":"b919c910_9ba6e5c7","updated":"2026-09-17 05:55:12.000000000","message":"Thanks for the detailed explanation and for adding the tests! I\u0027ll take a look at, too.","commit_id":"e73cf9c77a3d7ce0abde887d997975a7e3c11547"}]}
