Vagrant 使用中碰到的一个奇葩问题
碰到一个很无厘头的问题,跟大家分享一下。
今天公司突然断电,电脑重启之后 vagrant up
无法启动,报错:
C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/io.rb:32:in `encode': incomplete "\xB0" on GBK (Encoding::InvalidByteSequenceError)
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/io.rb:32:in `read_until_block'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/subprocess.rb:163:in `block in execute'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/subprocess.rb:161:in `each'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/subprocess.rb:161:in `execute'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/subprocess.rb:22:in `execute'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/base.rb:429:in `block in raw'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/busy.rb:19:in `busy'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/base.rb:428:in `raw'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/base.rb:367:in `block in execute'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/retryable.rb:17:in `retryable'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/base.rb:362:in `execute'
from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/version_5_1.rb:551:in `read_state'
...
看到这个错误有点懵逼了,从来没见过,而且网上根本搜不到类似的信息:incomplete "\xB0" on GBK (Encoding::InvalidByteSequenceError)
。\xB0 这个编码貌似是一个温度符号「°」的编码,而且从内容上看应该是哪里设置出问题了,这个字符 ruby 无法处理。
刚好前两天自己手动装了一个 virtual box 的桌面版 Ubuntu,想学学 c,还以为是安装的新系统出问题了,于是把那个系统所有的镜像配置文件都删掉,重新启动,故障依旧。
于是老老实实看错误信息,一个一个查。
首先看看 C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/lib/vagrant/util/io.rb
这个文件的 32 行:
data << io.readpartial(READ_CHUNK_SIZE).encode("UTF-8", Encoding.default_external)
这个是案发第一现场,io.readpartial
中的 IO 类是 ruby 中处理所有基本输入输出的一个类,readpartial
这个方法被设计来用来获取一个输入的「流」,并且要求提供最大的长度,在 io.rb 中这个值被设为 4096。
到这步的基本处理过程应该是 vagrant 获取某个数据,然后再转码成 "UTF-8",之后再继续处理。所以我的目标是找出获取什么数据的时候出错的。
继续往上查看方法的调用过程(也就是消息的传递过程), C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/base.rb:367
这个位置是一个 def execute(*command, &block)
方法,从注释可以知道,这个方法是解析一个命令并且返回输出:
Execute the given subcommand for VBoxManage and return the output.
再往上追溯,来到 C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.1/plugins/providers/virtualbox/driver/version_5_1.rb:551
的 read_state
方法,这个方法通过 VBoxManage.exe
来获取虚拟机的状态:
def read_state
output = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
if output =~ /^name="<inaccessible>"$/
return :inaccessible
elsif output =~ /^VMState="(.+?)"$/
return $1.to_sym
end
nil
end
到这里才发现是运行这个命令的时候出错了,于是手动在命令行中运行这个命令:
~\Oracle\VirtualBox\VBoxManage.exe showvminfo 1a0185d1-3d4d-4b05-ab79-0a90808882a9 --machinereadable
发现输出没有任何问题,根本没有什么特殊的字符串:
name="homestead-7"
groups="/"
ostype="Ubuntu (64-bit)"
UUID="1a0185d1-3d4d-4b05-ab79-0a90808882a9"
...
SnapshotUUID-1-1-1="53726207-4a4d-48ea-8db9-8d17eb8f7362"
SnapshotName-1-1-1-1="安装vim"
SnapshotUUID-1-1-1-1="a17c7d39-f032-4696-b06c-5ad85c36a15b"
CurrentSnapshotName="安装vim"
CurrentSnapshotUUID="a17c7d39-f032-4696-b06c-5ad85c36a15b"
CurrentSnapshotNode="SnapshotName-1-1-1-1"
中间省略了不少,有兴趣的可以自己试试看,VBoxManage.exe 在 virtual box 的安装目录下。
这个时候我又蒙了,根本没有「°」这个符号。
突然想到了之前的 io.readpartial
方法,这个方法的参数是一个数字,相当于到了获取到这么多数据的时候会做一个截断。会不会把某些中文刚好给截断了?从上面的信息可以看到,最近刚好做了一个镜像备份,备份的名称为 「安装vim」。
我去查了下,「安装」的 GBK 编码是 B0B2 D7B0
,这就是错误信息中 \xB0 的来源了,而且是「装」引起的,因为我把名称改为 「安vim」,可以正常启动。
坑爹,于是把备份的名称改成英文,正常启动。
这可能也跟 ruby 的 encode 方法有关:io.readpartial(READ_CHUNK_SIZE).encode("UTF-8", Encoding.default_external)
,在这里 vagrant 使用了两个参数,而中文可能被当成 GBK 编码来处理了。
这一路上的坑真的是太多了,一不小心就会掉进去,小伙伴如果碰到这种情况,可以优先考虑看看有没有可能是这个原因。
本作品采用《CC 协议》,转载必须注明作者和本文链接
人生苦短,我用mac
@leo 公司主要 .net 开发 :laughing:
所有有些习惯是非常好的,例如:不要使用中文名称命名、文件夹使用英文命名并且不包含特殊字符。 :smile:
@Summer 我一般都会比较注意,万万没想到那个也是一个坑 :sweat_smile:
妈蛋中枪了,直接用vb拍了个快照就不能启动了,vb默认快照名称是 “备份 + 数字”
兄弟!~ 你牛掰。我也遇到了同样的问题,快郁闷死了。真的把备份的镜像的名称里面【安装】的【装】去掉,重启虚拟机,就真的好了。感谢作者的分享,真的解决了问题。
我是电脑突然蓝屏了,再打开就遇到了和作者一样的错误。错误信息一模一样。
唯一不一样的是,我能力不足,惭愧。