)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":5112,"name":"Seyeong Kim","email":"seyeong.kim@canonical.com","username":"xtrusia"},"change_message_id":"a3575817946ff0e9f286e41348dfcd55724a8986","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"166ff859_e67a3d0f","updated":"2026-06-22 08:23:42.000000000","message":"LGTM on the code. I reproduced the issue and confirmed this patch fixes it.\n\nWithout the patch, when I remove an instance that is already gone from the metadata, the cluster-relation-departed hook fails and keeps retrying in a loop.\nThe remove-instance action also fails with \"Metadata for instance not found\". With the patch, the hook completes and the action returns success with your WARN log.\n\nI gave -1 only to ask one thing. can we add a zaza test for this?\nFor example, run remove-instance twice for the same address and check that the second call succeeds and shows the WARN message.(rough idea)\n\nThe test can go in the zaza-openstack-tests repo. We can run it with func-test-pr in the commit message, or with the test runner in stsstack-bundles.\n\nThanks.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":5112,"name":"Seyeong Kim","email":"seyeong.kim@canonical.com","username":"xtrusia"},"change_message_id":"ebf079001110c1b03f86f24ef9f6d5f1ec7c7e3e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"b87e2abd_db32aedd","updated":"2026-07-21 04:12:58.000000000","message":"maybe worth having discussion.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":38923,"name":"Jacob Hanks","display_name":"quanchobi","email":"jacob.hanks@canonical.com","username":"quanchobi"},"change_message_id":"02e0a536a3b51f1180e1874cef31c92f02d7e9b4","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"a5b7da9b_a983ed4e","in_reply_to":"166ff859_e67a3d0f","updated":"2026-09-15 14:15:05.000000000","message":"Will do! I haven\u0027t ran the func tests yet, but it looks like my code might break `test_800_remove_leader`, as it requires attempting to remove an already removed leader node to fail.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"}],"src/lib/charm/openstack/mysql_innodb_cluster.py":[{"author":{"_account_id":5112,"name":"Seyeong Kim","email":"seyeong.kim@canonical.com","username":"xtrusia"},"change_message_id":"ebf079001110c1b03f86f24ef9f6d5f1ec7c7e3e","unresolved":true,"context_lines":[{"line_number":1114,"context_line":"        _topology \u003d _status.get(\"defaultReplicaSet\", {}).get(\"topology\", {})"},{"line_number":1115,"context_line":"        # Topology keys are of the form \"address:port\"."},{"line_number":1116,"context_line":"        return any("},{"line_number":1117,"context_line":"            _member.rsplit(\":\", 1)[0] \u003d\u003d address for _member in _topology)"},{"line_number":1118,"context_line":""},{"line_number":1119,"context_line":"    def remove_instance(self, address, force\u003dFalse):"},{"line_number":1120,"context_line":"        \"\"\"Remove instance from the cluster"}],"source_content_type":"text/x-python","patch_set":2,"id":"c7b23ba6_7790e644","line":1117,"updated":"2026-07-21 04:12:58.000000000","message":"I haven\u0027t found many usage of urlsplit in charms, we may use urllib.parse.urlsplit to support both ipv4 and ipv6. maybe need another review.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":38923,"name":"Jacob Hanks","display_name":"quanchobi","email":"jacob.hanks@canonical.com","username":"quanchobi"},"change_message_id":"7191423053d6895f5ea01d7934acd6b2ebb44a67","unresolved":true,"context_lines":[{"line_number":1114,"context_line":"        _topology \u003d _status.get(\"defaultReplicaSet\", {}).get(\"topology\", {})"},{"line_number":1115,"context_line":"        # Topology keys are of the form \"address:port\"."},{"line_number":1116,"context_line":"        return any("},{"line_number":1117,"context_line":"            _member.rsplit(\":\", 1)[0] \u003d\u003d address for _member in _topology)"},{"line_number":1118,"context_line":""},{"line_number":1119,"context_line":"    def remove_instance(self, address, force\u003dFalse):"},{"line_number":1120,"context_line":"        \"\"\"Remove instance from the cluster"}],"source_content_type":"text/x-python","patch_set":2,"id":"a04363ab_bb8aa424","line":1117,"in_reply_to":"682e46be_1971ccd1","updated":"2026-09-16 15:17:53.000000000","message":"Ah, gotcha. That will be a simple fix. Just need to check if the first char is \u0027[\u0027, and strip off it and the closing bracket off if it is.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":5112,"name":"Seyeong Kim","email":"seyeong.kim@canonical.com","username":"xtrusia"},"change_message_id":"54468791c5e1f36735d5c774f86af4ec5691dd1f","unresolved":true,"context_lines":[{"line_number":1114,"context_line":"        _topology \u003d _status.get(\"defaultReplicaSet\", {}).get(\"topology\", {})"},{"line_number":1115,"context_line":"        # Topology keys are of the form \"address:port\"."},{"line_number":1116,"context_line":"        return any("},{"line_number":1117,"context_line":"            _member.rsplit(\":\", 1)[0] \u003d\u003d address for _member in _topology)"},{"line_number":1118,"context_line":""},{"line_number":1119,"context_line":"    def remove_instance(self, address, force\u003dFalse):"},{"line_number":1120,"context_line":"        \"\"\"Remove instance from the cluster"}],"source_content_type":"text/x-python","patch_set":2,"id":"682e46be_1971ccd1","line":1117,"in_reply_to":"6c3eaf75_94ed60fd","updated":"2026-09-16 08:08:01.000000000","message":"In case _member has [xxxx:xxx::x]:3306 and address has xxxx:xxx::x, if we only split by \u0027:\u0027, it could cause return false. so I mentioned it. for now I think there is no various ipv6 format check so just checking zaza test may not enough for this one. I think that ipv6 case is not common for current deployment, but I think it is possible.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":38923,"name":"Jacob Hanks","display_name":"quanchobi","email":"jacob.hanks@canonical.com","username":"quanchobi"},"change_message_id":"a3dd6d2086611725b6eae966780e032087fc55ab","unresolved":false,"context_lines":[{"line_number":1114,"context_line":"        _topology \u003d _status.get(\"defaultReplicaSet\", {}).get(\"topology\", {})"},{"line_number":1115,"context_line":"        # Topology keys are of the form \"address:port\"."},{"line_number":1116,"context_line":"        return any("},{"line_number":1117,"context_line":"            _member.rsplit(\":\", 1)[0] \u003d\u003d address for _member in _topology)"},{"line_number":1118,"context_line":""},{"line_number":1119,"context_line":"    def remove_instance(self, address, force\u003dFalse):"},{"line_number":1120,"context_line":"        \"\"\"Remove instance from the cluster"}],"source_content_type":"text/x-python","patch_set":2,"id":"4e2e51b3_851886cb","line":1117,"in_reply_to":"a04363ab_bb8aa424","updated":"2026-09-16 15:24:14.000000000","message":"Done","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":38923,"name":"Jacob Hanks","display_name":"quanchobi","email":"jacob.hanks@canonical.com","username":"quanchobi"},"change_message_id":"02e0a536a3b51f1180e1874cef31c92f02d7e9b4","unresolved":true,"context_lines":[{"line_number":1114,"context_line":"        _topology \u003d _status.get(\"defaultReplicaSet\", {}).get(\"topology\", {})"},{"line_number":1115,"context_line":"        # Topology keys are of the form \"address:port\"."},{"line_number":1116,"context_line":"        return any("},{"line_number":1117,"context_line":"            _member.rsplit(\":\", 1)[0] \u003d\u003d address for _member in _topology)"},{"line_number":1118,"context_line":""},{"line_number":1119,"context_line":"    def remove_instance(self, address, force\u003dFalse):"},{"line_number":1120,"context_line":"        \"\"\"Remove instance from the cluster"}],"source_content_type":"text/x-python","patch_set":2,"id":"6c3eaf75_94ed60fd","line":1117,"in_reply_to":"c7b23ba6_7790e644","updated":"2026-09-15 14:15:05.000000000","message":"@seyeong.kim@canonical.com func tests passed:\n```\nubuntu@stg-reproducer-quanchobi-ps7-project-bastion:~/charm-mysql-innodb-cluster$ $HOME/stsstack-bundles/openstack_functest_runner.sh  --skip-build --func-test-pr 1417\n\u003ctruncated\u003e\n2026-08-11 16:54:50 [INFO] test_801_remove_leader_idempotent (zaza.openstack.charm_tests.mysql.tests.MySQLInnoDBClusterScaleTest)\n2026-08-11 16:54:50 [INFO] Remove leader node a second time to test idempotency.\n2026-08-11 16:54:50 [INFO]  ...\n2026-08-11 16:54:50 [INFO] Scale in idempotent test: remove leader again\n2026-08-11 16:54:50 [INFO] Wait till model is idle ...\n2026-08-11 16:54:50 [INFO] Calling remove-instance a second time on 10.159.28.188\n2026-08-11 16:54:52 [INFO] ok\n2026-08-11 16:54:52 [INFO] test_802_add_unit (zaza.openstack.charm_tests.mysql.tests.MySQLInnoDBClusterScaleTest)\n\u003ctruncated\u003e\n  func-target: OK (2561.61\u003dsetup[5.14]+cmd[2556.48] seconds)\n  congratulations :) (2561.86 seconds)\nDestroy model \u0027zaza-6847625891af\u0027 and run next test? [ENTER]\nDestroying model\nWaiting for model to be removed, 8 machine(s), 7 application(s).........\nWaiting for model to be removed, 3 machine(s)...\nWaiting for model to be removed....\nModel destroyed.\n\nTest results for charm mysql-innodb-cluster functional tests @ commit e01de91:\n  * noble: SUCCESS\n\nResults also saved to /tmp/tmp.zspdqaMb7P-charm-func-test-results\n```\n\nIf you\u0027d like me to take a look at `urllib.parse.urlsplit`, I can do that, but it might be outside of the scope of this review if it\u0027s not used anywhere in the tests.","commit_id":"3a240785ce98e93bf15649947c42e42b65fa3e43"},{"author":{"_account_id":5112,"name":"Seyeong Kim","email":"seyeong.kim@canonical.com","username":"xtrusia"},"change_message_id":"2a56947c1792c119949132406b94cce8dde05b3c","unresolved":true,"context_lines":[{"line_number":1118,"context_line":"            _address \u003d address"},{"line_number":1119,"context_line":"        for _member in _topology:"},{"line_number":1120,"context_line":"            # IPv6 endpoints are formatted as \"[address]:port\"."},{"line_number":1121,"context_line":"            _member_address \u003d _member.rsplit(\":\", 1)[0]"},{"line_number":1122,"context_line":"            if (_member_address.startswith(\"[\") and"},{"line_number":1123,"context_line":"                    _member_address.endswith(\"]\")):"},{"line_number":1124,"context_line":"                _member_address \u003d _member_address[1:-1]"}],"source_content_type":"text/x-python","patch_set":4,"id":"b100f699_f3ad94e7","line":1121,"updated":"2026-09-18 01:54:59.000000000","message":"you don\u0027t have to implement it manually. you can use urllib.parse.urlsplit()\nlike\nmember_address \u003d urllib.parse.urlsplit(\n    \"//{}\".format(endpoint)\n).hostname\n\ncomparing address with ipaddress.ip_address(x) looks good.","commit_id":"8dc64c9a8086ec50a413fca7ff76593cabef2c9d"}]}
