Vagrant detach.vdi文件在销毁之前或仅在';不要把它拿走

Vagrant detach.vdi文件在销毁之前或仅在';不要把它拿走,vagrant,Vagrant,在Vagrant文件中,我附加手动创建的db.vdi磁盘: vb.customize [ 'storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', 'db.vdi' ] 它的工作原理很好,但当我销毁流浪者盒子这个文件被删除。我试着修理那个流浪汉的触发器before:destroybefore:hal

在Vagrant文件中,我附加手动创建的
db.vdi
磁盘:

vb.customize [
  'storageattach', :id, 
  '--storagectl', 'SATA Controller', 
  '--port', 1, '--device', 0, 
  '--type', 'hdd', 
  '--medium', 'db.vdi'
]
它的工作原理很好,但当我销毁流浪者盒子这个文件被删除。我试着修理那个流浪汉的触发器
before:destroy
before:halt
不工作,我得到一个错误,驱动器不可热插拔<代码>之后:暂停根本不起作用:

config.trigger.after :halt do
  run "VBoxManage storageattach '#{@machine.id}'" +
    " --storagectl 'SATA Controller' --port 1 --device 0 --type hdd --medium none"
end
我想做的是,当我运行
vagrant destroy
时,我想优雅地停止机器,删除vdi文件,这样vagrant就不会删除它,而是销毁其他所有内容

可能吗


编辑:

看起来可以用插件挂钩来实现这一点-请参阅
Action.detach_storage
的参考资料,但我不知道如何在这个文件中使用它

  config.trigger.after :halt do
    info "dettach drive"
    machineId = File.read(".vagrant/machines/default/virtualbox/id")
    run "VBoxManage storageattach '#{machineId}'" +
      " --storagectl 'SATAController' --port 1 --device 0 --type hdd --medium none"
  end

请参阅@FrédéricHenri-分离触发得太早:

==> default: Running triggers before destroy...
==> default: dettach drive
==> !!! TOO SOON !!!
==> default: Executing command "VBoxManage storageattach d0132b78-11ea-41cf-b003-dac15536520c --storagectl SATAController --port 1 --device 0 --type hdd --medium none"...
==> default: Command execution finished.
    default: Are you sure you want to destroy the 'default' VM? [y/N] y

==> default: Forcing shutdown of VM...
==> !!! THIS IS WHERE I SHOULD DETACH THE DRIVE !!!
==> default: Destroying VM and associated drives...
我找到了这个插件


它看起来像我所需要的,但不幸的是,只有一个磁盘有选项

我认为您是正确的,就像您查看示例插件一样,它们在halt命令之后和销毁之前进行挂钩

获取机器Id 问题在于您运行命令的方式。
run“VBoxManage-storageattach'.{@machine.id}'。
将返回一个空的
machine.id
;Vagrantfile脚本中的vagrant不知道它正在构建的机器,因此会出现一个错误,即它找不到ID/名称为空的引用VM,并且该命令无法成功执行

您需要的是获取VirtualBox VM Id,以便将其传递给命令;此Id保存在文件
.vagrant/machines///Id
中,假设您没有为VM设置特定的名称,它将是:

在销毁触发器之前使用 销毁VM时弹出驱动器时出现热插拔错误 对于热插拔pat,您需要确保文件在连接时确实是热插拔的,以便在VM仍在运行时(即销毁之前)可以将其拔下

您可以在连接硬盘驱动器时从文件中进行此配置

vb.customize [
  'storageattach', :id, 
  '--storagectl', 'SATAController', 
  '--port', 1, '--device', 0, 
  '--type', 'hdd', 
  '--medium', 'db.vdi',
  '--hotpluggable', 'on'
]
为此VM运行
destroy
命令时

fhenri:~/project/vagrant/drive$ vagrant destroy
==> default: Running triggers before destroy...
==> default: dettach drive
==> default: Executing command "VBoxManage storageattach d0132b78-11ea-41cf-b003-dac15536520c --storagectl SATAController --port 1 --device 0 --type hdd --medium none"...
==> default: Command execution finished.
    default: Are you sure you want to destroy the 'default' VM? [y/N] y

==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
因此,您可以清楚地看到命令已正确执行,驱动器已卸下,我可以看到驱动器仍在本地硬盘上,然后我可以回答“是”以销毁VM文件

使用后停止触发器 在我这方面,它和后停触发钩也一样好:

从流浪汉档案

  config.trigger.after :halt do
    info "dettach drive"
    machineId = File.read(".vagrant/machines/default/virtualbox/id")
    run "VBoxManage storageattach '#{machineId}'" +
      " --storagectl 'SATAController' --port 1 --device 0 --type hdd --medium none"
  end
将运行

fhenri:~/project/vagrant/drive$ vagrant halt
==> default: Attempting graceful shutdown of VM...
==> default: Running triggers after halt...
==> default: dettach drive
==> default: Executing command "VBoxManage storageattach 74274ab6-173e-4934-9864-33e09be26214 --storagectl SATAController --port 1 --device 0 --type hdd --medium none"...
==> default: Command execution finished.
对于您来说,剩下的问题是确保在这种情况下不调用destroy,因为destroy不会停止VM,它只是销毁它,这样它就不会调用halt命令并绕过halt触发器,您可以使用额外的detroy插件,但这将意味着您不想要的热插拔功能

如果驱动器已连接,则防止损坏 通过检查
vboxmanage showvminfo
并查找storagecontrollerportcount0的值,可以检查设备上连接的驱动器数量

你可以在销毁触发器之前将其转换

  config.trigger.before :destroy do
    vm_info = `vboxmanage showvminfo #{@machine.id} --machinereadable | grep storagecontrollerportcount0`
    value = Integer(vm_info.split("=")[1].gsub('"','').chomp())
    raise Vagrant::Errors::VagrantError.new, "drive attached - cannot be destroyed" if value > 1
  end

如果您连接了多个驱动器,并且无法继续执行销毁命令,则会引发错误。我已在windows7主机上使用vagrant 2.1.1(2.1.2已损坏触发器)和fedora guest(奇怪的是,它有一个IDE控制器)对其进行了测试

因此,我的解决方案,也许是愚蠢的,如下所示:

config.trigger.after :halt do |x| 
machID = "./.vagrant/machines/default/virtualbox/id"
if File.file?(machID)
    machineID = File.read(".vagrant/machines/default/virtualbox/id")
end
if defined?(machineID)
    x.run = {inline: "VBoxManage storageattach '#{machineID}' 
    --storagectl 'IDE' --port 1 --device 0 --type hdd --medium none"}
end



config.trigger.before :destroy do |x|
x.name = "Halting machine"
x.run = {inline: "vagrant halt default"}
end
因此,基本上,当您调用触发器destroy“before”时,它首先停止机器(对于“halt”之后的触发器),分离磁盘,然后调用destroy。它可以在运行的机器和停止的机器上工作。所以是一种持久性磁盘


顺便说一句,这可能需要一些保护措施来解决这一切

看来你并不是唯一要求这样做的人@是的。我甚至不需要整个插件,我可以自己重新分区并创建磁盘,我只想在最终停止和销毁之间将其分离。我100%确信,使用vagrant触发器,插件
“{@machine.id}”
不是空的,我在尝试之前回显了命令,机器id不是空的,命令是正确的。问题是我需要在最终停止和销毁之间分离驱动器。好的,也许插件暴露了机器对象-在销毁之前是你想要的步骤,如果你运行这个,它会在用VM文件销毁驱动器之前分离驱动器,所以文件将保留在驱动器上。问题是我不想让它热插拔!我想在运行
vagrant destroy
时停止机器、分离和销毁。Vagrant正在尝试分离工作虚拟机上的驱动器,热插拔驱动器可能会导致数据丢失。。。“销毁前是您想要的步骤”否,
config.trigger.before:destroy do
在计算机仍在运行时被触发,您甚至可以在回答“执行命令VBoxManage storageattach”和“强制关闭VM…”时看到它。确定您想要在停止后,它工作正常,但不要调用detroy,然后,销毁不会停止VM,因此,它绕过了暂停触发器,并将删除您的驱动器(除非您也有销毁触发器,但要使此触发器工作,您需要热插拔功能)