Triggered by Gerrit: https://gerrit.opensdn.io/c/opensdn-io/tf-controller/+/3034 Obtained pipelines/main.groovy from git https://github.com/opensdn-io/tf-jenkins.git [Pipeline] Start of Pipeline [Pipeline] timestamps [Pipeline] { [Pipeline] timeout [2026-08-26T13:02:41.729Z] Timeout set to expire in 8 hr 0 min [Pipeline] { [Pipeline] node [2026-08-26T13:02:41.773Z] Running on slave-openstack-gz1_1 in /home/jenkins/workspace/pipeline-post-merge [Pipeline] { [Pipeline] stage [Pipeline] { (init) [Pipeline] cleanWs [2026-08-26T13:02:41.853Z] [WS-CLEANUP] Deleting project workspace... [2026-08-26T13:02:41.853Z] [WS-CLEANUP] Deferred wipeout is disabled by the job configuration... [2026-08-26T13:02:41.943Z] [WS-CLEANUP] done [Pipeline] checkout [2026-08-26T13:02:41.969Z] The recommended git tool is: git [2026-08-26T13:02:41.974Z] No credentials specified [2026-08-26T13:02:41.976Z] Cloning the remote Git repository [2026-08-26T13:02:41.978Z] Cloning repository https://github.com/opensdn-io/tf-jenkins.git [2026-08-26T13:02:41.979Z] > git init /home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins # timeout=10 [2026-08-26T13:02:41.984Z] Fetching upstream changes from https://github.com/opensdn-io/tf-jenkins.git [2026-08-26T13:02:41.984Z] > git --version # timeout=10 [2026-08-26T13:02:41.986Z] > git --version # 'git version 2.25.1' [2026-08-26T13:02:41.986Z] > git fetch --tags --force --progress -- https://github.com/opensdn-io/tf-jenkins.git +refs/heads/*:refs/remotes/origin/* # timeout=10 [2026-08-26T13:02:43.255Z] Avoid second fetch [2026-08-26T13:02:43.261Z] Checking out Revision 9c86492d4a22712d2c3b4ab27040cd93556012b4 (refs/remotes/origin/master) [2026-08-26T13:02:43.314Z] Commit message: "Merge "install cloud-init from site mirror"" [2026-08-26T13:02:43.245Z] > git config remote.origin.url https://github.com/opensdn-io/tf-jenkins.git # timeout=10 [2026-08-26T13:02:43.248Z] > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10 [2026-08-26T13:02:43.257Z] > git rev-parse refs/remotes/origin/master^{commit} # timeout=10 [2026-08-26T13:02:43.262Z] > git config core.sparsecheckout # timeout=10 [2026-08-26T13:02:43.265Z] > git checkout -f 9c86492d4a22712d2c3b4ab27040cd93556012b4 # timeout=10 [2026-08-26T13:02:43.315Z] > git rev-list --no-walk 9c86492d4a22712d2c3b4ab27040cd93556012b4 # timeout=10 [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/utils/gerrit.groovy) [Pipeline] } [Pipeline] // load [Pipeline] echo [2026-08-26T13:02:43.621Z] INFO: resolved gerrit URL is https://gerrit.opensdn.io/ [Pipeline] sh [2026-08-26T13:02:43.919Z] + /home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/infra/gerrit/resolve_patchsets.py --gerrit https://gerrit.opensdn.io/ --review I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615 --branch master --changed_files --output /home/jenkins/workspace/pipeline-post-merge/patchsets-info.json [Pipeline] archiveArtifacts [2026-08-26T13:02:43.951Z] Archiving artifacts [Pipeline] sh [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/utils/gerrit.groovy) [Pipeline] } [Pipeline] // load [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/constants.groovy) [Pipeline] } [Pipeline] // load [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/utils/config.groovy) [Pipeline] } [Pipeline] // load [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/utils/jobs.groovy) [Pipeline] } [Pipeline] // load [Pipeline] load [Pipeline] { (/home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/pipelines/utils/gate.groovy) [Pipeline] } [Pipeline] // load [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Pre-build) [Pipeline] echo [2026-08-26T13:02:46.018Z] Logs URL: http://nexus.gz1.opensdn.io:8082/jenkins_logs/gerrit/34/3034/3/post-merge_953 [Pipeline] echo [2026-08-26T13:02:46.047Z] terminate_runs_by_review_number: start [Pipeline] echo [2026-08-26T13:02:46.321Z] terminate_runs_by_review_number: terminated builds = [] [Pipeline] sh [Pipeline] echo [2026-08-26T13:02:46.694Z] Pipeline to run: post-merge [Pipeline] sh [Pipeline] sh [Pipeline] archiveArtifacts [2026-08-26T13:02:47.334Z] Archiving artifacts [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] readYaml [Pipeline] echo [2026-08-26T13:02:48.199Z] WARNING: project opensdn-io/tf-controller doesn't define pipeline post-merge [Pipeline] echo [2026-08-26T13:02:48.215Z] Streams from config: [:] [Pipeline] echo [2026-08-26T13:02:48.230Z] Jobs from config: [:] [Pipeline] echo [2026-08-26T13:02:48.246Z] Post Jobs from config: [:] [Pipeline] echo [2026-08-26T13:02:48.277Z] Notify gerrit verified=null, submit=false, msg= [2026-08-26T13:02:48.277Z] TF CI Build Started (post-merge) https://jenkins.opensdn.io/job/pipeline-post-merge/953/ [Pipeline] withCredentials [2026-08-26T13:02:48.304Z] Masking supported pattern matches of $GERRIT_API_PASSWORD [Pipeline] { [Pipeline] echo [2026-08-26T13:02:48.355Z] INFO: resolved gerrit URL is https://gerrit.opensdn.io/ [Pipeline] sh [2026-08-26T13:02:48.644Z] + /home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/infra/gerrit/notify.py --gerrit https://gerrit.opensdn.io/ --user tf-gerrit --password **** --review I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615 --patchset 3 --branch master --message 'TF CI Build Started (post-merge) https://jenkins.opensdn.io/job/pipeline-post-merge/953/' [2026-08-26T13:02:48.903Z] DEBUG: Change: {'id': 'opensdn-io%2Ftf-controller~master~I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615', 'project': 'opensdn-io/tf-controller', 'branch': 'master', 'topic': 'route-target-lifecycle', 'attention_set': {}, 'removed_from_attention_set': {'1000003': {'account': {'_account_id': 1000003}, 'last_update': '2026-08-26 07:01:32.000000000', 'reason': ' replied on the change', 'reason_account': {'_account_id': 1000003}}, '1000001': {'account': {'_account_id': 1000001}, 'last_update': '2026-08-20 08:23:10.000000000', 'reason': 'removed on reply'}, '1000021': {'account': {'_account_id': 1000021}, 'last_update': '2026-08-26 13:02:23.000000000', 'reason': 'Change was submitted'}}, 'hashtags': [], 'change_id': 'I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615', 'subject': 'ST: always release the logical-router route-target ID on delete', 'status': 'MERGED', 'created': '2026-08-06 06:10:38.000000000', 'updated': '2026-08-26 13:02:23.000000000', 'submitted': '2026-08-26 13:02:23.000000000', 'submitter': {'_account_id': 1000001}, 'insertions': 38, 'deletions': 6, 'total_comment_count': 10, 'unresolved_comment_count': 1, 'has_review_started': True, 'submission_id': '3034-route-target-lifecycle', 'meta_rev_id': 'eb89fa8126c78ae055d517e15893954b4f9ae144', '_number': 3034, 'owner': {'_account_id': 1000021}, 'labels': {'Code-Review': {'all': [{'value': 2, 'date': '2026-08-26 10:02:42.000000000', 'permitted_voting_range': {'min': 2, 'max': 2}, '_account_id': 1000003}, {'value': 0, '_account_id': 1000001}], 'values': {'-2': 'This shall not be submitted', '-1': 'I would prefer this is not submitted as is', ' 0': 'No score', '+1': 'Looks good to me, but someone else must approve', '+2': 'Looks good to me, approved'}, 'description': '', 'default_value': 0}, 'Verified': {'all': [{'value': 0, '_account_id': 1000003}, {'value': 2, 'date': '2026-08-26 13:02:12.000000000', 'permitted_voting_range': {'min': 2, 'max': 2}, '_account_id': 1000001}], 'values': {'-2': 'Fails', '-1': 'Fails', ' 0': 'No score', '+1': 'Verified', '+2': 'Gating'}, 'description': '', 'default_value': 0}}, 'permitted_labels': {'Code-Review': [' 0', '+1', '+2'], 'Verified': ['+2']}, 'removable_labels': {}, 'removable_reviewers': [{'_account_id': 1000002}], 'reviewers': {'REVIEWER': [{'_account_id': 1000001}, {'_account_id': 1000003}], 'CC': [{'_account_id': 1000002}]}, 'pending_reviewers': {}, 'current_revision': 'bf640c0e985af7951b386684af01e66c5de7e548', 'revisions': {'bf640c0e985af7951b386684af01e66c5de7e548': {'kind': 'REWORK', '_number': 3, 'created': '2026-08-20 10:54:43.000000000', 'uploader': {'_account_id': 1000021}, 'ref': 'refs/changes/34/3034/3', 'fetch': {'ssh': {'url': 'ssh://tf-gerrit@gerrit.opensdn.io:29418/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}, 'anonymous http': {'url': 'https://gerrit.opensdn.io/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}, 'http': {'url': 'https://tf-gerrit@gerrit.opensdn.io/a/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}}, 'commit': {'parents': [{'commit': '9112407ed0a26aaec3ee49b7513d267bf7e93597', 'subject': 'Switching to oneTBB: old includes removal'}], 'author': {'name': 'Charnsilp Chinprasert(Nipa)', 'email': 'justice.form@gmail.com', 'date': '2026-08-06 06:05:31.000000000', 'tz': 420}, 'committer': {'name': 'Charnsilp Chinprasert(Nipa)', 'email': 'justice.form@gmail.com', 'date': '2026-08-20 10:54:21.000000000', 'tz': 420}, 'subject': 'ST: always release the logical-router route-target ID on delete', 'message': "ST: always release the logical-router route-target ID on delete\n\nLogicalRouterST.delete_obj() runs five steps before it releases the\nroute-target ID, and every one of them is an API or datastore call that can\nraise:\n\n update_multiple_refs('virtual_machine_interface', {})\n update_multiple_refs('route_table', {})\n update_multiple_refs('bgpvpn', {})\n update_virtual_networks()\n delete_route_targets([self.route_target])\n asn = ...get_autonomous_system()\n self._object_db.free_route_target(self.name, asn)\n\nIf any of them raises, free_route_target() never runs and the ID stays\nallocated. Nothing recovers it: the logical router is gone, so delete_obj()\nis never called again, and a Zookeeper index with no row in route_target_table\nhas no reader - alloc_route_target() starts from the row, so an index without\none is never examined.\n\nA production config DB shows six route_target_table bindings naming logical\nrouters that no longer exist. Three of them still have their route-target\nobject and three do not, which places the failure between delete_route_targets()\nand free_route_target() in the first case and at or before\ndelete_route_targets() in the second.\n\nRead the ASN before the steps that can raise, and release the ID in a finally\nblock, so it is released on every path. The ASN lookup is deliberately outside\nthe try: if it stayed inside and raised - which is one of the two things that\nexplains the three-case split above - the finally clause would have no asn to\nuse.\n\nEach teardown step is attempted independently rather than under one try, so a\nfailure in an early step does not skip the later ones and the log names the\nstep that actually failed. Raised in review on patchset 1.\n\nThe per-step handling is about diagnosis rather than damage, and it is worth\nbeing precise about why. None of the five steps leaves unrecoverable state on\nits own: RouteTargetST.reinit() already deletes route-target objects that have\nno routing-instance or logical-router back-refs, and walks _RT_CF freeing any\nrow whose object is gone (resources/route_target.py:20-38); the ref sets are\nrebuilt from the DB at the same reinit. The ID release is the one step with no\nsuch collector - alloc_route_target() starts from the _RT_CF row, so a\nZookeeper index whose row is gone is never examined again - which is why it,\nand only it, sits in finally.\n\nOne consequence to note: update_virtual_networks() reads the ref sets that the\nearlier steps clear, so if an earlier step fails it works from stale membership\nand may leave a route target on a VN. That is now logged instead of being\nhidden behind an abandoned try, and reinit recomputes it. It does not justify\nskipping the steps after it.\n\nThe catch is deliberately broad. The goal is that the release below always\nruns, and narrowing it to the vnc_api exception family would let anything\nunexpected skip the remaining steps again. If the project would rather see it\nnarrowed, say so and I will.\n\nThis does not make delete_obj() idempotent, and it does not help if\nfree_route_target() itself raises partway - that is handled separately.\n\nTested on this patchset: tox -e pep8 passes clean. tox -e py39 runs 83 tests\nwith 16 skipped and one failure, test_security_group.test_stale_acl, which\nfails the same way on an unpatched tree - it hashes a dict in\n_access_control_list_update() and is unrelated to this change.\n\nChange-Id: I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615\nSigned-off-by: Charnsilp Chinprasert(Nipa) \n"}}}, 'requirements': [], 'submit_records': [{'rule_name': 'gerrit~DefaultSubmitRule', 'status': 'CLOSED', 'labels': [{'label': 'Code-Review', 'status': 'OK', 'applied_by': {'_account_id': 1000003}}, {'label': 'Verified', 'status': 'OK', 'applied_by': {'_account_id': 1000001}}]}]} [2026-08-26T13:02:48.903Z] DEBUG: push message data: {'labels': {}, 'message': 'TF CI Build Started (post-merge) https://jenkins.opensdn.io/job/pipeline-post-merge/953/'} [Pipeline] } [Pipeline] // withCredentials [Pipeline] echo [2026-08-26T13:02:49.044Z] Notify discord for new job is started [Pipeline] echo [2026-08-26T13:02:49.088Z] INFO: resolved gerrit URL is https://gerrit.opensdn.io/ [Pipeline] echo [2026-08-26T13:02:49.116Z] Notify discord msg= [2026-08-26T13:02:49.116Z] The review was merged. [2026-08-26T13:02:49.116Z] [ST: always release the logical-router route-target](https://gerrit.opensdn.io/c/opensdn-io/tf-controller/+/3034) [Pipeline] withCredentials [2026-08-26T13:02:49.142Z] Masking supported pattern matches of $DISCORD_WEBHOOK_URL [Pipeline] { [Pipeline] writeFile [Pipeline] sh [2026-08-26T13:02:49.483Z] % Total % Received % Xferd Average Speed Time Time Time Current [2026-08-26T13:02:49.483Z] Dload Upload Total Spent Left Speed [2026-08-26T13:02:50.412Z] [2026-08-26T13:02:50.412Z] 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 [2026-08-26T13:02:50.412Z] 100 184 0 0 100 184 0 203 --:--:-- --:--:-- --:--:-- 203 [2026-08-26T13:02:50.412Z] 100 184 0 0 100 184 0 203 --:--:-- --:--:-- --:--:-- 203 [Pipeline] } [Pipeline] // withCredentials [Pipeline] } [Pipeline] // stage [Pipeline] echo [2026-08-26T13:02:50.544Z] Jobs results: [:] [Pipeline] stage [Pipeline] { (gerrit vote) [Pipeline] echo [2026-08-26T13:02:50.603Z] Notify gerrit verified=null, submit=false, msg= [2026-08-26T13:02:50.603Z] TF CI Build Succeeded (post-merge) in 0h 0m 4s [2026-08-26T13:02:50.603Z] [2026-08-26T13:02:50.603Z] Succeeded checks: [Pipeline] withCredentials [2026-08-26T13:02:50.626Z] Masking supported pattern matches of $GERRIT_API_PASSWORD [Pipeline] { [Pipeline] echo [2026-08-26T13:02:50.685Z] INFO: resolved gerrit URL is https://gerrit.opensdn.io/ [Pipeline] sh [2026-08-26T13:02:50.988Z] + /home/jenkins/workspace/pipeline-post-merge/src/opensdn-io/tf-jenkins/infra/gerrit/notify.py --gerrit https://gerrit.opensdn.io/ --user tf-gerrit --password **** --review I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615 --patchset 3 --branch master --message 'TF CI Build Succeeded (post-merge) in 0h 0m 4s [2026-08-26T13:02:50.988Z] [2026-08-26T13:02:50.988Z] Succeeded checks:' [2026-08-26T13:02:50.989Z] DEBUG: Change: {'id': 'opensdn-io%2Ftf-controller~master~I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615', 'project': 'opensdn-io/tf-controller', 'branch': 'master', 'topic': 'route-target-lifecycle', 'attention_set': {}, 'removed_from_attention_set': {'1000003': {'account': {'_account_id': 1000003}, 'last_update': '2026-08-26 07:01:32.000000000', 'reason': ' replied on the change', 'reason_account': {'_account_id': 1000003}}, '1000001': {'account': {'_account_id': 1000001}, 'last_update': '2026-08-20 08:23:10.000000000', 'reason': 'removed on reply'}, '1000021': {'account': {'_account_id': 1000021}, 'last_update': '2026-08-26 13:02:23.000000000', 'reason': 'Change was submitted'}}, 'hashtags': [], 'change_id': 'I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615', 'subject': 'ST: always release the logical-router route-target ID on delete', 'status': 'MERGED', 'created': '2026-08-06 06:10:38.000000000', 'updated': '2026-08-26 13:02:48.000000000', 'submitted': '2026-08-26 13:02:23.000000000', 'submitter': {'_account_id': 1000001}, 'insertions': 38, 'deletions': 6, 'total_comment_count': 10, 'unresolved_comment_count': 1, 'has_review_started': True, 'submission_id': '3034-route-target-lifecycle', 'meta_rev_id': '8233ae8531ef5a31485077bef8959def68a12ce7', '_number': 3034, 'owner': {'_account_id': 1000021}, 'labels': {'Code-Review': {'all': [{'value': 2, 'date': '2026-08-26 10:02:42.000000000', 'permitted_voting_range': {'min': 2, 'max': 2}, '_account_id': 1000003}, {'value': 0, '_account_id': 1000001}], 'values': {'-2': 'This shall not be submitted', '-1': 'I would prefer this is not submitted as is', ' 0': 'No score', '+1': 'Looks good to me, but someone else must approve', '+2': 'Looks good to me, approved'}, 'description': '', 'default_value': 0}, 'Verified': {'all': [{'value': 0, '_account_id': 1000003}, {'value': 2, 'date': '2026-08-26 13:02:12.000000000', 'permitted_voting_range': {'min': 2, 'max': 2}, '_account_id': 1000001}], 'values': {'-2': 'Fails', '-1': 'Fails', ' 0': 'No score', '+1': 'Verified', '+2': 'Gating'}, 'description': '', 'default_value': 0}}, 'permitted_labels': {'Code-Review': [' 0', '+1', '+2'], 'Verified': ['+2']}, 'removable_labels': {}, 'removable_reviewers': [{'_account_id': 1000002}], 'reviewers': {'REVIEWER': [{'_account_id': 1000001}, {'_account_id': 1000003}], 'CC': [{'_account_id': 1000002}]}, 'pending_reviewers': {}, 'current_revision': 'bf640c0e985af7951b386684af01e66c5de7e548', 'revisions': {'bf640c0e985af7951b386684af01e66c5de7e548': {'kind': 'REWORK', '_number': 3, 'created': '2026-08-20 10:54:43.000000000', 'uploader': {'_account_id': 1000021}, 'ref': 'refs/changes/34/3034/3', 'fetch': {'ssh': {'url': 'ssh://tf-gerrit@gerrit.opensdn.io:29418/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}, 'anonymous http': {'url': 'https://gerrit.opensdn.io/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}, 'http': {'url': 'https://tf-gerrit@gerrit.opensdn.io/a/opensdn-io/tf-controller', 'ref': 'refs/changes/34/3034/3'}}, 'commit': {'parents': [{'commit': '9112407ed0a26aaec3ee49b7513d267bf7e93597', 'subject': 'Switching to oneTBB: old includes removal'}], 'author': {'name': 'Charnsilp Chinprasert(Nipa)', 'email': 'justice.form@gmail.com', 'date': '2026-08-06 06:05:31.000000000', 'tz': 420}, 'committer': {'name': 'Charnsilp Chinprasert(Nipa)', 'email': 'justice.form@gmail.com', 'date': '2026-08-20 10:54:21.000000000', 'tz': 420}, 'subject': 'ST: always release the logical-router route-target ID on delete', 'message': "ST: always release the logical-router route-target ID on delete\n\nLogicalRouterST.delete_obj() runs five steps before it releases the\nroute-target ID, and every one of them is an API or datastore call that can\nraise:\n\n update_multiple_refs('virtual_machine_interface', {})\n update_multiple_refs('route_table', {})\n update_multiple_refs('bgpvpn', {})\n update_virtual_networks()\n delete_route_targets([self.route_target])\n asn = ...get_autonomous_system()\n self._object_db.free_route_target(self.name, asn)\n\nIf any of them raises, free_route_target() never runs and the ID stays\nallocated. Nothing recovers it: the logical router is gone, so delete_obj()\nis never called again, and a Zookeeper index with no row in route_target_table\nhas no reader - alloc_route_target() starts from the row, so an index without\none is never examined.\n\nA production config DB shows six route_target_table bindings naming logical\nrouters that no longer exist. Three of them still have their route-target\nobject and three do not, which places the failure between delete_route_targets()\nand free_route_target() in the first case and at or before\ndelete_route_targets() in the second.\n\nRead the ASN before the steps that can raise, and release the ID in a finally\nblock, so it is released on every path. The ASN lookup is deliberately outside\nthe try: if it stayed inside and raised - which is one of the two things that\nexplains the three-case split above - the finally clause would have no asn to\nuse.\n\nEach teardown step is attempted independently rather than under one try, so a\nfailure in an early step does not skip the later ones and the log names the\nstep that actually failed. Raised in review on patchset 1.\n\nThe per-step handling is about diagnosis rather than damage, and it is worth\nbeing precise about why. None of the five steps leaves unrecoverable state on\nits own: RouteTargetST.reinit() already deletes route-target objects that have\nno routing-instance or logical-router back-refs, and walks _RT_CF freeing any\nrow whose object is gone (resources/route_target.py:20-38); the ref sets are\nrebuilt from the DB at the same reinit. The ID release is the one step with no\nsuch collector - alloc_route_target() starts from the _RT_CF row, so a\nZookeeper index whose row is gone is never examined again - which is why it,\nand only it, sits in finally.\n\nOne consequence to note: update_virtual_networks() reads the ref sets that the\nearlier steps clear, so if an earlier step fails it works from stale membership\nand may leave a route target on a VN. That is now logged instead of being\nhidden behind an abandoned try, and reinit recomputes it. It does not justify\nskipping the steps after it.\n\nThe catch is deliberately broad. The goal is that the release below always\nruns, and narrowing it to the vnc_api exception family would let anything\nunexpected skip the remaining steps again. If the project would rather see it\nnarrowed, say so and I will.\n\nThis does not make delete_obj() idempotent, and it does not help if\nfree_route_target() itself raises partway - that is handled separately.\n\nTested on this patchset: tox -e pep8 passes clean. tox -e py39 runs 83 tests\nwith 16 skipped and one failure, test_security_group.test_stale_acl, which\nfails the same way on an unpatched tree - it hashes a dict in\n_access_control_list_update() and is unrelated to this change.\n\nChange-Id: I48b6aa7a1c5904c6b68afa3ae8ec4e7d367c3615\nSigned-off-by: Charnsilp Chinprasert(Nipa) \n"}}}, 'requirements': [], 'submit_records': [{'rule_name': 'gerrit~DefaultSubmitRule', 'status': 'CLOSED', 'labels': [{'label': 'Code-Review', 'status': 'OK', 'applied_by': {'_account_id': 1000003}}, {'label': 'Verified', 'status': 'OK', 'applied_by': {'_account_id': 1000001}}]}]} [2026-08-26T13:02:50.989Z] DEBUG: push message data: {'labels': {}, 'message': 'TF CI Build Succeeded (post-merge) in 0h 0m 4s\n\nSucceeded checks:'} [Pipeline] } [Pipeline] // withCredentials [Pipeline] sh [Pipeline] archiveArtifacts [2026-08-26T13:02:51.381Z] Archiving artifacts [Pipeline] withCredentials [2026-08-26T13:02:51.434Z] Masking supported pattern matches of $LOGS_HOST_SSH_KEY [Pipeline] { [Pipeline] writeFile [Pipeline] sh [2026-08-26T13:02:51.778Z] Warning: Permanently added 'nexus.gz1.opensdn.io,212.233.90.199' (ECDSA) to the list of known hosts. [2026-08-26T13:02:52.341Z] Warning: Permanently added 'nexus.gz1.opensdn.io,212.233.90.199' (ECDSA) to the list of known hosts. [Pipeline] } [Pipeline] // withCredentials [Pipeline] } [Pipeline] // stage [Pipeline] echo [2026-08-26T13:02:54.006Z] URL of console output = https://jenkins.opensdn.io/job/pipeline-post-merge/953/consoleText [Pipeline] withCredentials [2026-08-26T13:02:54.038Z] Masking supported pattern matches of $LOGS_HOST_SSH_KEY [Pipeline] { [Pipeline] sh