2013-07-11 23 views
5

Đây là mảnh của tôi về Ruby trong một công thức Chef:Kiểm tra cho thư mục hiện có thất bại trong Ruby + Chef

# 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 

Kết quả là:

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 

Tôi biết rằng /vol/postgres/data tồn tại và là một thư mục , nhưng nó vẫn cố gắng thực hiện mv. Tại sao?

Chỉ cần chắc chắn, chạy kịch bản Ruby độc lập sau trên kết quả đầu ra cùng một máy "nomv":

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

Hmm ... Nếu đó là Đầu bếp, hãy thử '! :: File.exist? ...'. Nó có thể được trộn với Chef :: Provider :: File. –

+0

@DracoAter Tôi đã hy vọng đó là nó, nhưng tôi đã cố gắng, và tiếc là nó làm cho không có sự khác biệt. –

Trả lời

7

Tôi đã không quá chu đáo trước đó, tôi nghĩ rằng bạn đang kiểm tra cho sự tồn tại tập tin trong not_if hoặc only_if khối. Vấn đề của bạn tương tự như vấn đề trong câu hỏi này: Chef LWRP - defs/resources execution order. Xem giải thích chi tiết ở đó.

Vấn đề của bạn là mã !File.exist?("/vol/postgres/data") được thực hiện ngay lập tức - (vì nó là ruby ​​thuần túy), trước khi bất kỳ tài nguyên nào được thực thi và do đó trước khi cài đặt sau.

Giải pháp nên là di chuyển séc đến khối not_if.

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

Đúng vậy! Tôi không biết rằng tài nguyên không được thực thi ngay lập tức. Một 'not_if' giải quyết vấn đề này, nhưng tôi có một công thức khác trong đó nhiều' execute' được bao bọc trong một 'if' duy nhất. Tuy nhiên, tôi không thể chỉ thêm điều kiện vào mỗi tài nguyên 'execute', bởi vì cái đầu tiên làm cho nó' false'. Làm thế nào tôi có thể áp dụng điều kiện đó? –

+0

Thêm điều kiện 'not_if' vào tài nguyên đầu tiên. Thêm 'action: nothing' vào tất cả những thứ khác.Thêm thông báo theo cách mà mọi tài nguyên 'execute' thông báo cho tài nguyên tiếp theo chạy ngay lập tức. –

0

tôi sẽ sử dụng, !File.directory?("/vol/postgres/data")

0

Bạn gọi đó là bên trong ứng dụng ray của bạn hoặc nó là một tập tin ruby ​​độc lập.

Nếu bạn đang làm trong ứng dụng đường ray của mình.

Sau đó,

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

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

Bạn cần chỉ định đường dẫn tệp cụ thể từ gốc.

+1

Đó là một công thức đầu bếp, và con đường là tuyệt đối, vì vậy đó không phải là vấn đề. –

0

Tìm kiếm nhanh trên google sẽ trả về rất nhiều câu trả lời về "di chuyển giữa các thiết bị không thành công". Ruby chỉ truyền lỗi do hệ điều hành trả về; điều này không liên quan gì đến việc kiểm tra tệp khi các câu trả lời khác cho biết.

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

này có phần đơn giản miễn là chúng ta hiểu khái niệm. mv hoặc di chuyển không thực sự di chuyển tệp/thư mục đến một vị trí khác trong cùng một thiết bị, nó chỉ thay thế con trỏ trong khu vực đầu tiên của thiết bị của bạn. Con trỏ (trong bảng inode) sẽ được di chuyển, nhưng không có gì thực sự được sao chép. Điều này sẽ làm việc miễn là bạn ở trong cùng một phương tiện/thiết bị.

Bây giờ, khi bạn di chuyển tệp từ thiết bị này sang thiết bị khác (/ dev/sda1 đến/dev/sdb1), bạn sẽ gặp phải lỗi “di chuyển giữa các thiết bị không thành công, không thể xóa mục tiêu: Là thư mục”. Điều này xảy ra khi mv phải thực sự di chuyển dữ liệu của bạn sang một thiết bị khác, nhưng không thể loại bỏ inode/pointer, vì nếu nó đã làm thì sẽ không có dữ liệu nào để quay trở lại, và nếu nó không hoạt động mv thì không thực sự hoàn thành bởi vì chúng tôi sẽ kết thúc với dữ liệu trong nguồn. Damned nếu bạn làm và damned nếu bạn không, vì vậy nó khôn ngoan không để làm điều đó để bắt đầu với!

Trong trường hợp này, cp là tốt nhất. Sao chép dữ liệu của bạn và sau đó xóa nguồn của bạn theo cách thủ công.

Một giải pháp tốt hơn có thể chỉ cần sử dụng công cụ ruby ​​thay vì thực hiện một lệnh shell, vì nó nói 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

Tôi nghĩ rằng bạn đang đọc quá nhiều vào phần đầu của thông báo lỗi. Kết thúc rõ ràng nói: "không thể loại bỏ mục tiêu: Là một thư mục", tức là, '/ vol/postgres/data' tồn tại (mà tôi biết nó để làm). –

+0

Bây giờ tôi đã xác minh độc lập rằng '/ vol/postgres/data' không tồn tại (vì vậy không chỉ' mv' nói như vậy) có nghĩa là hành vi 'mv' là không liên quan; nó không nên thực thi chút nào. –

+0

bạn có quyền đọc thư mục không? – DGM

5

Sử dụng khối mã này:

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

HOẶC

bạn cũng có thể sử dụng

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

Cả hai sẽ chỉ chạy lệnh nếu /vol/postgres/data không có trong hệ thống tệp. Nếu bạn muốn chạy khối lệnh sau đó sử dụng một cái gì đó như thế này,

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

tôi sử dụng

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

Để kiểm tra xem một thư mục tồn tại, bạn có thể sử dụng một equvivalent của File.exists đó là Dir.exist:

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

Như những người khác chỉ ra, bạn nên sử dụng not_if hoặc only_if thay vì sử dụng điều kiện Ruby đơn giản, vì vậy tôi sẽ không giải thích lại. Kiểm tra câu trả lời của Draco để biết chi tiết.

execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do 
    not_if { Dir.exist?("/vol/postgres/data") } 
end 
Các vấn đề liên quan