2013-07-11 2 views
5

Questo è il mio pezzo di Ruby in una ricetta Chef:Verificare la directory esistente non riesce in 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 

Il risultato è:

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 

So che /vol/postgres/data esiste ed è una directory , tuttavia tenta ancora di eseguire il mv. Perché?

Giusto per essere sicuri, eseguendo il seguente script di Ruby standalone sulle stesse uscite della macchina "nomv":

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

Hmm ... Se è Chef, prova '! :: File.exist? ...'. Può essere miscelato con Chef :: Provider :: File. –

+0

@DracoAter Speravo fosse, ma ci ho provato, e sfortunatamente non fa differenza. –

risposta

7

non ero così attento in precedenza, ho pensato che si sta verificando per il file esistenza nel not_if o only_if blocco. Il tuo problema è simile a quello in questa domanda: Chef LWRP - defs/resources execution order. Vedi la spiegazione dettagliata lì.

Il tuo problema è che il codice !File.exist?("/vol/postgres/data") viene eseguito immediatamente - (perché è puro rubino), prima che qualsiasi risorsa venga eseguita e quindi prima che il post-evento sia installato.

La soluzione deve essere quella di spostare il controllo sul blocco not_if.

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

Ecco fatto! Non ero a conoscenza del fatto che le risorse non vengono eseguite immediatamente. Un 'not_if' risolve questo problema, ma ho un'altra ricetta in cui multipli' execute's sono racchiusi in un singolo 'if'. Tuttavia, non posso semplicemente aggiungere una condizione a ciascuna risorsa 'execute', perché la prima la rende' false'. Come potrei applicare la condizione lì? –

+0

Aggiungi la condizione 'not_if' alla prima risorsa. Aggiungi "azione: niente" a tutti gli altri.Aggiungi notifiche in modo che ogni risorsa 'execute' notifichi la successiva da eseguire immediatamente. –

0

userei, !File.directory?("/vol/postgres/data")

0

stai chiamando all'interno dell'applicazione rails o è un file rubino standalone.

Se stai facendo nella tua app di rotaie.

Poi,

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

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

È necessario specificare il percorso del file particolare da root.

+1

È una ricetta da Chef e il percorso è assoluto, quindi non è questo il problema. –

0

Una ricerca rapida su google genera molte risposte relative a "spostamento inter-dispositivo non riuscito". Ruby sta solo passando lungo l'errore restituito dal sistema operativo; questo non ha nulla a che fare con il test del file, come indicano le altre risposte.

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

Questo è un po semplice fino a quando abbiamo capito il concetto. mv o move non sposta effettivamente il file/cartella in un'altra posizione all'interno dello stesso dispositivo, sostituisce semplicemente il puntatore nel primo settore del dispositivo. Il puntatore (nella tabella degli inode) verrà spostato, ma non viene effettivamente copiato nulla. Questo funzionerà fintanto che rimani all'interno dello stesso supporto/dispositivo.

Ora, quando si tenta di spostare i file da un dispositivo a un altro (/ dev/sda1 a/dev/sdb1) si eseguirà "Errore inter-dispositivo non riuscito, impossibile rimuovere la destinazione: è una directory". Questo succede quando mv deve effettivamente spostare i tuoi dati su un altro dispositivo, ma non può rimuovere l'inode/puntatore, perché se lo facesse, non ci sarebbero dati a cui tornare, e se così non fosse, allora l'operazione mv non è veramente completa perché finiremo con i dati nella fonte. Dannato se lo fai e dannato se non lo fai, quindi è saggio non farlo per cominciare!

In tale situazione cp è il migliore. Copia i tuoi dati e poi rimuovi manualmente la tua fonte.

Una soluzione migliore potrebbe essere quella di utilizzare solo strumenti rubino anziché eseguire un comando shell, poiché dice 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

Penso che stai leggendo troppo nella prima parte del messaggio di errore. La fine dice chiaramente: "impossibile rimuovere il bersaglio: esiste una directory", cioè, "/ vol/postgres/data" esiste (che so di fare). –

+0

Ora ho verificato in modo indipendente che '/ vol/postgres/data' esiste (quindi non solo' mv' dice così) il che significa che il comportamento di 'mv' è irrilevante; non dovrebbe affatto funzionare. –

+0

hai il permesso di leggere la cartella? – DGM

5

Usa questo blocco di codice:

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

O

puoi anche usare

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

Entrambi eseguiranno il comando solo se /vol/postgres/data non è presente nel file system. Se si desidera eseguire blocco di comandi quindi utilizzare qualcosa di simile,

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

Io uso

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

Per verificare se esiste una directory è possibile utilizzare un equvivalent di File.exists che è Dir.exist:

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

Come altri hanno sottolineato, è necessario utilizzare not_if o only_if invece di usare la semplice condizione Ruby, quindi non ho intenzione di spiegarlo di nuovo. Controlla la risposta di Draco per i dettagli.

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