5

这是我在厨师食谱中的一块红宝石:

# if datadir doesn't exist, move over the default one
if !File.exist?("/vol/postgres/data")
    execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
end

结果是:

Executing mv /var/lib/postgresql/9.1/main /vol/postgres/data
mv: inter-device move failed: `/var/lib/postgresql/9.1/main' to `/vol/postgres/data/main'; unable to remove target: Is a directory

我知道它/vol/postgres/data存在并且是一个目录,但它仍然尝试执行mv. 为什么?

可以肯定的是,在同一台机器上运行以下独立 Ruby 脚本会输出“nomv”:

if !File.exist?("/vol/postgres/data")
print "mv"
else
print "nomv"
end
4

7 回答 7

9

我之前没有那么专心,我以为您正在检查文件是否存在not_ifonly_if阻止。您的问题类似于此问题中的问题:Chef LWRP - defs/resources execution order。请参阅那里的详细说明。

您的问题是!File.exist?("/vol/postgres/data")代码在执行任何资源之前以及在安装 postgress 之前立即执行(因为它是纯 ruby​​)。

解决方案应该是将支票移动到not_if阻止。

execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do
  not_if { File.exist?("/vol/postgres/data") }
end
于 2013-07-12T07:57:08.943 回答
5

使用此代码块:

execute "name" do
    command "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
    not_if { ::File.exists?("/vol/postgres/data")}
end

或者

你也可以使用

execute "name" do
    command "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
    creates "/vol/postgres/data"
end

/vol/postgres/data仅当文件系统中不存在时,两者才会运行该命令。如果你想运行命令块然后使用这样的东西,

bash 'name' do
  not_if { ::File.exists?("/vol/postgres/data") }
  cwd "/"
  code <<-EOH
  mv /var/lib/postgresql/9.1/main /vol/postgres/data
  #any other bash commands 
  #any other bash commands
  EOH
end
于 2013-07-12T05:46:55.683 回答
1

我用

!::File.directory?(::File.join('path/to/directory', 'directory_name'))
于 2014-03-10T13:31:17.640 回答
1

要测试一个目录是否存在,您可以使用以下等价File.existsDir.exist

Dir.exist?("/vol/postgres/data")

正如其他人指出的那样,您应该使用not_iforonly_if而不是使用普通的 Ruby 条件,所以我不再解释它。详情请查看 Draco 的回答。

execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do
  not_if { Dir.exist?("/vol/postgres/data") }
end
于 2016-02-29T01:31:48.807 回答
0

我会用,!File.directory?("/vol/postgres/data")

于 2013-07-11T14:42:20.390 回答
0

您是在 Rails 应用程序中调用它还是它是一个独立的 ruby​​ 文件。

如果您正在使用您的 Rails 应用程序。

然后,

File.exist?("#{Rails.root}/ur-file-path")

例如:File.exist?("#{Rails.root}/public/ur-filename")

您需要从根目录指定特定的文件路径。

于 2013-07-11T14:55:33.660 回答
0

一个快速的谷歌搜索出现了很多关于“设备间移动失败”的答案。Ruby 只是传递操作系统返回的错误;正如其他答案所示,这与测试文件无关。

来自:http: //insanelabs.com/linux/linux-cannot-move-folders-inter-device-move-failed-unable-to-remove-target-is-a-directory/

只要我们理解这个概念,这有点简单。mv 或 move 实际上不会将文件/文件夹移动到同一设备内的另一个位置,它只是替换设备第一个扇区中的指针。指针(在 inode 表中)将被移动,但实际上并没有被复制。只要您留在同一媒体/设备中,这将起作用。

现在,当您尝试将文件从一个设备移动到另一个设备(/dev/sda1 到 /dev/sdb1)时,您将遇到“设备间移动失败,无法删除目标:是目录”错误。当 mv 必须实际将您的数据移动到另一个设备时会发生这种情况,但无法删除 inode/指针,因为如果这样做了,那么将没有数据可以回退,如果没有,则 mv 操作并未真正完成因为我们最终会得到源中的数据。如果你这样做该死,如果你不这样做该死,所以从一开始就不这样做是明智的!

在这种情况下,cp 是最好的。复制您的数据,然后手动删除您的源。

更好的解决方案可能是只使用 ruby​​ 工具而不是执行 shell 命令,因为它说如果 file 和 dest 存在于不同的磁盘分区上,则复制该文件,然后删除原始文件。

FileUtils.mv '/var/lib/postgresql/9.1/main', '/vol/postgres/data'
于 2013-07-11T15:24:09.623 回答