2013-07-11 22 views
5

這是我在廚師配方一塊紅寶石:檢查現有目錄中的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。爲什麼?

只是可以肯定,運行在同一臺機器上輸出「NOMV」以下獨立Ruby腳本:

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

嗯......如果是廚師,試試'!:: File.exist?...'。它可能與Chef :: Provider :: File混合。 –

+0

@DracoAter我對此有希望,但我已經嘗試過了,不幸的是它沒有任何區別。 –

回答

7

我不早了這麼周到,我還以爲你是在not_ifonly_if塊檢查文件的存在。您的問題與此問題中的問題類似:Chef LWRP - defs/resources execution order。請參閱此處的詳細說明。

你的問題是!File.exist?("/vol/postgres/data")代碼被直接執行 - (因爲它是純ruby),在任何資源被執行之前,因此在postgress被安裝之前。

解決方案應該是將支票移至not_if區塊。

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

就是這樣!我不知道資源不會立即執行。 'not_if'解決了這個問題,但是我有另一個配方,其中多個'execute's被包裝在一個'if'中。但是,我不能只爲每個'execute'資源添加一個條件,因爲第一個使它成爲'false'。我怎麼能適用那裏的情況? –

+0

將'not_if'條件添加到第一個資源。向所有其他人添加「action:nothing」。以這樣的方式添加通知:每個「執行」資源通知下一個立即運行。 –

0

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

0

你Rails應用程序內調用它或者它是一個獨立的ruby文件。

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

然後,

File.exist( 「#{Rails.root}/UR-文件路徑」)

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

您需要從根目錄指定特定的文件路徑。

+1

這是一個廚師的食譜,路徑是絕對的,所以這不是問題。 –

0

快速谷歌搜索出現了很多關於「設備間移動失敗」的答案。 Ruby只是傳遞操作系統返回的錯誤;這與其他答案顯示的測試文件無關。

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

這隻要我們理解這個概念有點簡單。 mv或​​移動實際上不會將文件/文件夾移動到同一設備中的另一個位置,它只會替換設備第一個扇區中的指針。指針(在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' 
+0

我覺得你對錯誤信息的第一部分太多了。最後清楚地說:「無法刪除目標:是一個目錄」,即存在'/ vol/postgres/data'(我知道它是這麼做的)。 –

+0

我現在已經獨立驗證過'/ vol/postgres/data'確實存在(所以不僅僅是'mv'這麼說),這意味着'mv'的行爲是不相關的;它根本不應該執行。 –

+0

你有權限閱讀該文件夾嗎? – DGM

5

使用的代碼塊:

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

OR你可以使用

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 
1

我用

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

爲了測試是否存在一個目錄,你可以使用File.existsDir.exist的equvivalent:

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

正如其他人所指出的,你應該使用not_ifonly_if而不是使用普通的Ruby條件,所以我不打算再解釋一遍。查看Draco的答案瞭解詳情。

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