Skip to content

Conversation

@brlin-tw
Copy link
Contributor

@brlin-tw brlin-tw commented Nov 4, 2025

Disclaimer: This pull request is entirely generated by GitHub Copilot using the "Code with agent mode", I have no ability to understand and validate it at the moment and is only served as reference only.

When a VirtualBox VM has snapshots, the primary disk location may be under the Snapshots subdirectory, causing path comparison with other disks to fail. Update the comparison logic to also consider the parent directory of the Snapshots folder, allowing existing extra disks to be found and preventing attempts to recreate them that would result in VERR_ALREADY_EXISTS errors.

Fixes #13352

The following is the transcript that lead up to the patch(Apologies for the Chinese text, it isn't intentional):

brlin-tw: Using a very simple Vagrantfile for testing purposes I can reproduce the following unexpected behaviour.

Vagrantfile in use:

Vagrant.configure(2) do |config|
  config.vm.box = "alpine/alpine64"
  config.vm.disk :disk, size: "10MB", name: "data"
end

vagrant up succeeds, containing the output:

default: Disk 'data' not found in guest. Creating and attaching disk to guest...

as expected. Calling vagrant reload does succeed at this point.

Now create a snapshot:

$ vagrant snapshot save default base
==> default: Snapshotting the machine as 'base'...
==> default: Snapshot saved! You can restore the snapshot at any time by
==> default: using `vagrant snapshot restore`. You can delete it using
==> default: `vagrant snapshot delete`.

And now, while trying to reload:

$ vagrant reload
==> default: Attempting graceful shutdown of VM...
==> default: Checking if box 'alpine/alpine64' version '3.7.0' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Configuring storage mediums...
    default: Disk 'data' not found in guest. Creating and attaching disk to guest...
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["createmedium", "--filename", "/home/nvimtest/VirtualBox VMs/test_default_1708697784014_9523/data.vdi", "--sizebyte", "10485760", "--format", "VDI"]

Stderr: 0%...VBOX_E_FILE_ERROR
VBoxManage: error: Failed to create medium
VBoxManage: error: Could not create the medium storage unit '/home/nvimtest/VirtualBox VMs/test_default_1708697784014_9523/data.vdi'.
VBoxManage: error: VDI: cannot create image '/home/nvimtest/VirtualBox VMs/test_default_1708697784014_9523/data.vdi' (VERR_ALREADY_EXISTS)
VBoxManage: error: Details: code VBOX_E_FILE_ERROR (0x80bb0004), component MediumWrap, interface IMedium
VBoxManage: error: Context: "RTEXITCODE handleCreateMedium(HandlerArg*)" at line 630 of file VBoxManageDisk.cpp

The root cause seems to be at

File.dirname(d["Location"]) == File.dirname(primary[:location]) &&

The comparison File.dirname(d["Location"]) == File.dirname(primary[:location]) does not yield true, because after creating the snapshot, primary[:location] looks like /home/nvimtest/VirtualBox VMs/test_default_1708696655312_30742/Snapshots while the extra disks d["Location"] is /home/nvimtest/VirtualBox VMs/test_default_1708696655312_30742. As the disks name is derived from the image file name and the snapshot lacks the actual name, the snapshot of the additional disk is not taken into account.

$ VBoxManage list hdds
[...]
UUID:           ccbf1111-39ce-4003-bf2e-2f2ec675b81b
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /home/nvimtest/VirtualBox VMs/test_default_1708697784014_9523/data.vdi
Storage format: VDI
Capacity:       10 MBytes
Encryption:     disabled

UUID:           d4c5b37b-69b4-4b79-aa3c-c219fca581cd
Parent UUID:    ccbf1111-39ce-4003-bf2e-2f2ec675b81b
State:          created
Type:           normal (differencing)
Location:       /home/nvimtest/VirtualBox VMs/test_default_1708697784014_9523/Snapshots/{d4c5b37b-69b4-4b79-aa3c-c219fca581cd}.vdi
Storage format: VDI
Capacity:       10 MBytes
Encryption:     disabled

As this output is parsed to get the disk's name, {d4c5b37b-69b4-4b79-aa3c-c219fca581cd} does not match the expected name data.

Expected behavior

The box should reload and use the existing additional disk.

Actual behavior

The reload tries to recreate the already existing additional disk and failes.

Reproduction information

See explanation at the top.

Vagrant version

2.4.1

Virtualbox version

7.0.12

Host operating system

Ubuntu 22.04

Guest operating system

Tried with debian, ubuntu and alpine

GitHub Copilot: 我會先建立任務清單,再讀取並修改 configure_disks.rb,最後執行快速語法檢查以驗證變更。目標是讓磁碟比對能處理 VirtualBox 的 Snapshots 子目錄情況,避免重新建立已存在的磁碟。接下來我會依序執行讀檔、修改、驗證三個步驟。

已建立 4 個待辦事項

讀取 ,1 至 400 行

讀取 ,400 至 442 行

我要修改比對邏輯:先讀取檔案並套用小幅修正,使得當 primary disk path 在 Snapshots 子目錄時也會比對到其他磁碟位置,然後做一次 Ruby 語法檢查;我將先套用修改。

正在使用 "套用修補檔"


Ran terminal command: ruby -c /workspaces/vagrant/plugins/providers/virtualbox/cap/configure_disks.rb

已完成 (1/4) Read file

簡短說明(我做了什麼)

我修正了 configure_disks.rb 在尋找已存在的額外磁碟時的路徑比對邏輯。修正目標是解決在 VirtualBox snapshot 情況下,primary disk path 會位於 Snapshots 子目錄而導致比對失敗(進而嘗試重建已存在磁碟)的問題。

我已:

  • 修改比對邏輯,當 primary path 的父目錄是 Snapshots 時,同時將 Snapshots 目錄的 parent 也列入候選比對目錄。
  • 執行一次 Ruby 語法檢查(ruby -c),結果為 Syntax OK

變更檔案

  • configure_disks.rb — 修正 disk-location 的比對邏輯,加入 primary_dir_candidates(包含原本 dirname,若 basename 為 Snapshots 再加入其 parent dirname),用以判斷 list_hdds 中的 Location 是否屬於候選目錄之一。

目的:讓 snapshot 的 differencing disk(位於 .../Snapshots/{uuid}.vdi)或原始磁碟(位於 .../VM_FOLDER/data.vdi)都能被正確比對到相同 VM,避免誤判「未存在」而去重新建立磁碟。

為何這能解決你的案例

你原先的情形:

  • 原始磁碟:/home/.../test_default_xxx/data.vdi
  • snapshot differencing:/home/.../test_default_xxx/Snapshots/{uuid}.vdi
  • primary[:location] 在 snapshot 之後會指向 Snapshots 路徑,所以原本的單一 File.dirname(primary[:location])File.dirname(d["Location"]) 無法相等,因而沒找到 data 這個 Disk Name。

新的邏輯會將 Snapshots 的 parent folder 也當成比對候選之一,因此能成功找到 data,避免重新建立磁碟導致的衝突(VERR_ALREADY_EXISTS)。

如何在你的環境驗證(建議步驟)

  1. 在修改後的分支或本地專案中啟用你原先的簡單 Vagrantfile:
    Vagrant.configure(2) do |config|
      config.vm.box = "alpine/alpine64"
      config.vm.disk :disk, size: "10MB", name: "data"
    end
    
  2. vagrant up(應成功並建立磁碟)
  3. vagrant snapshot save default base
  4. vagrant reload — 應該不會再嘗試重新建立 data,而會成功重新啟動。

(我無法在這裡跑整個 VirtualBox + Vagrant 的實機驗證,但已修正程式碼比對邏輯且通過 Ruby 語法檢查。)

備註與延伸想法

  • 我採取了最小且穩健的修正:只在 primary 的 dirname 是 Snapshots 時考慮 parent dirname。這可涵蓋大多數 VirtualBox snapshot 路徑情形,且影響範圍小。
  • 若你願意,可擴展比對邏輯:將候選目錄擴充為所有 ancestor 目錄(but 可能過於寬鬆)。目前的修法比較保守且直接對應到常見情境。
  • 若你希望我也加上一個單元測試(若專案已有測試框架)或嘗試在 CI 中跑一次整體情境驗證(需要 VirtualBox 環境),我可以進一步協助。

如果你想,我可以:

  • 把這個修改在新的 branch 上開一個 PR 範本(需要 repo 許可與遠端操作)。
  • 或是把更寬鬆的比對(所有 ancestor)改成一個選項並加入配置開關。

已進行變更。

brlin-tw: Commit the change with the commit author set to yourself, also enable --signoff:

GitHub Copilot: 我將使用 run_in_terminal 來設置 git 作者資訊並提交變更,包含 --signoff 選項。

Ran terminal command: git config user.name "GitHub Copilot" && git config user.email "[email protected]" && git add plugins/providers/virtualbox/cap/configure_disks.rb && git commit -s -m "virtualbox/cap: 修正 snapshot 中額外磁碟的路徑比對邏輯

在 VirtualBox snapshot 情境下,primary disk 的位置可能會在 Snapshots
子目錄中,這會導致與其他磁碟的路徑比對失敗。修改比對邏輯以同時考慮
Snapshots 目錄的父目錄,這樣可以正確找到已存在的額外磁碟,避免
嘗試重新建立而導致 VERR_ALREADY_EXISTS 錯誤。

Fixes #XXXX"

brlin-tw: Use English as the commit message instead, the corresponding GitHub issue number is 13352.

GitHub Copilot: 我將使用英文提交訊息並加入正確的 issue 編號。

Ran terminal command: git config user.name "GitHub Copilot" && git config user.email "[email protected]" && git add plugins/providers/virtualbox/cap/configure_disks.rb && git commit -s -m "virtualbox/cap: fix path comparison for extra disks in snapshots

When a VirtualBox VM has snapshots, the primary disk location may be under
the Snapshots subdirectory, causing path comparison with other disks to
fail. Update the comparison logic to also consider the parent directory
of the Snapshots folder, allowing existing extra disks to be found and
preventing attempts to recreate them that would result in VERR_ALREADY_EXISTS
errors.

Fixes #13352"

變更已成功提交!commit 訊息包含了問題的描述、解決方案以及對應的 issue 編號(#13352)。現在這個修改已經在你的本地倉庫中了。由於這是一個 fork,如果你想將這個修改提交到上游倉庫,你需要:

  1. 推送到你的 fork:
git push origin main
  1. 然後在 GitHub 上從你的 fork 創建一個 Pull Request 到 hashicorp/vagrant 倉庫。

需要我協助執行這些後續步驟嗎?

When a VirtualBox VM has snapshots, the primary disk location may be under
the Snapshots subdirectory, causing path comparison with other disks to
fail. Update the comparison logic to also consider the parent directory
of the Snapshots folder, allowing existing extra disks to be found and
preventing attempts to recreate them that would result in VERR_ALREADY_EXISTS
errors.

Fixes hashicorp#13352

Signed-off-by: GitHub Copilot <[email protected]>
@brlin-tw brlin-tw requested a review from a team as a code owner November 4, 2025 01:52
@hashicorp-cla-app
Copy link

CLA assistant check

Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement

Learn more about why HashiCorp requires a CLA and what the CLA includes


GitHub Copilot seems not to be a GitHub user.
You need a GitHub account to be able to sign the CLA.
If you have already a GitHub account, please add the email address used for this commit to your account.

Have you signed the CLA already but the status is still pending? Recheck it.

@brlin-tw brlin-tw marked this pull request as draft November 4, 2025 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Snapshotting leads to subsequent errors with additional disks

1 participant