在Ruby + Chef中检查现有目录是否失败

时间:2013-07-11 14:37:24

标签: ruby chef

这是我在厨师食谱中的Ruby:

# 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

7 个答案:

答案 0 :(得分:9)

我之前并不那么专注,我以为你正在检查not_ifonly_if块中是否存在文件。您的问题类似于此问题中的问题:Chef LWRP - defs/resources execution order。请参阅那里的详细解释。

你的问题是!File.exist?("/vol/postgres/data")代码会立即被执行 - (因为它是纯粹的红宝石),在执行任何资源之前,因此在安装postgress之前。

解决方案应该是将检查移至not_if阻止。

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

答案 1 :(得分: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

答案 2 :(得分:1)

我用

!::File.directory?(::File.join('path/to/directory', 'directory_name'))

答案 3 :(得分:1)

要测试目录是否存在,您可以使用File.exists的等效Dir.exist?("/vol/postgres/data")

not_if

正如其他人指出的那样,你应该使用only_ifexecute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do not_if { Dir.exist?("/vol/postgres/data") } end 而不是使用普通的Ruby条件,所以我不打算再解释一下。详情请查看Draco的答案。

{{1}}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

您是在rails应用程序中调用它还是独立的ruby文件。

如果您正在使用rails应用程序。

然后,

<强> File.exist?( “#{Rails.root} / UR-文件路径”)

Ex:File.exist?(“#{Rails.root} / public / ur-filename”)

您需要从root指定特定的文件路径。

答案 6 :(得分: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命令,因为它说If file and dest exist on the different disk partition, the file is copied then the original file is removed.

FileUtils.mv '/var/lib/postgresql/9.1/main', '/vol/postgres/data'