2

I have written a bash script which detects if a .ldif file has been written into a directory and if written, executes an ldapadd command and then deletes that file. The scripts is as follows:

dir="/home/myuser/newldif/"
        while inotifywait -e create "$dir"; do
              ldapadd -w "ldappassword" -D "cn=Manager,dc=mydomain,dc=com" -f /home/myuser/newldif/user.ldif
              rm -rf /home/myuser/newldif/user.ldif
        done

The script is executed like so:

nohup ./testscript &

The directory newldif is initially empty. When the file user.ldif is copied to this location, the script executes but skips the ldapadd command and executes the rm command.

On the other hand, when I execute the script without inotify (i.e. I removed the while loop completely), it adds the ldap entry and then deletes the file.

Is there anything wrong with the inotify syntax? The slapd logs don't show any errors. The nohup.out file simply shows the following output:

Setting up watches.
Watches established.
Setting up watches.
Watches established.
Setting up watches.
Watches established.

(each "Setting up watches." statement is for one deleted file)

The OS is CentOS 6.4 and OpenLDAP version is openldap-2.4.23.

rahuL
  • 692
  • 3
  • 12
  • 31
  • Force bash with a `#!/bin/bash` as the first line of the script. Add a `set -x` to your script to get a trace of what's happening. FWIW this works as expected on a system I have to hand. – user9517 Aug 23 '13 at 08:23
  • @Iain - `#!/bin/bash` is already the first line of the script. Where do I add the `set -x`? – rahuL Aug 23 '13 at 08:27
  • second line is a good start. – user9517 Aug 23 '13 at 08:48
  • Ok. This is the output after including `set -x` - `ldapadd -w ldappassword -D cn=Manager,dc=mydomain,dc=com -f /home/myuser/newldif/user.ldif` - For some reason, the quotes around the password and the rootdn have been removed. Is that what is causing it to skip the `ldapadd` command? – rahuL Aug 23 '13 at 08:58

1 Answers1

1

If the rm is executing from this script then there is nothing wrong with your logic.

It's probably a timing issue where the file is created in the directory but not populated when your script runs the ldap command. Try adding a cat of the file to see. Then try waiting for a close_write event on the directory instead so you have a fully populated file. This may also not be sufficient, as it depends on how you write to the file. Generally the safest way is to create a temporary file elsewhere then move that into place when fully populated, as this is a more atomic file system operation.

Also, adding some error checking for files you expect or commands is also a good idea:

#!/usr/bin/env bash

dir="/home/myuser/newldif/"
file="user.ldif.tmp"
ldf="$dir/$file"

while inotifywait -e close_write "$dir"; do

  # Check if the file we want exists in the directory being monitored. 
  if [ ! -f $ldf ]; then 
    echo "No file [$ldf]"; 
    continue;
  fi

  # Add users via ldap
  echo "Adding users:"
  mv $ldf $dir/user.ldif
  ldapadd -w "ldappassword" -D "cn=Manager,dc=mydomain,dc=com" -f $dir/user.ldif || echo "failed adding users" && exit 1

  # Remove file when done
  echo "Removing file"
  rm $dir/user.ldif || echo "failed removing file" && exit 1
done
rahuL
  • 692
  • 3
  • 12
  • 31
Matt
  • 1,559
  • 8
  • 11
  • The other commands like `echo`, `rm`, `cp`, `mv` and `ls` (these are the ones I tried) work within the `while` loop. As far as writing to the file is concerned, the file in it's entirety is being copied from another machine directly into this location. – rahuL Aug 23 '13 at 09:13
  • that same ldap command works outside of the script though? – Matt Aug 23 '13 at 09:20
  • yes. Also, if I run the script without the `while inotifywait...`, it adds the ldap entry successfully. – rahuL Aug 23 '13 at 09:23
  • Sorry, what is `inotifywait...`? If you're copying a remote file then, the file is created locally, then copied over the network, then closed. You are watching the 'create' event. Trying copying to `user.ldif.tmp`, then moving to `user.ldif`. Alternatively, what does code above produce? – Matt Aug 23 '13 at 09:28
  • The above code doesn't give any output (`cat $ldf`). I am trying your suggestion of a temp file as we speak. – rahuL Aug 23 '13 at 09:38
  • Copying to user.ldif.tmp, then moving to user.ldif worked!! :) Phew!! Thanks mindthemonkey and @Iain - I learnt some new things today... Could you edit the answer so that I can accept it please? – rahuL Aug 23 '13 at 10:06
  • I was expecting you would do that in the remote script that creates the user.ldif file!? i'e `gen ldif && scp ldif remote:/tmp/user.ldif.tmp && ssh remote "mv /tmp/user.ldif.tmp /home/user/newldif/user.ldif"` or some such. Where did you do the copy? – Matt Aug 23 '13 at 10:11
  • the ldif file was copied from the remote machine to the current machine via scp (and named with extension .tmp). Then the script in the current machine removes the .tmp extention (using `mv`) and then runs `ldapadd`; In essence two scripts - one on the remote machine to generate the ldif and copy it here and the second one on the current machine to add it to the LDAP directory. – rahuL Aug 23 '13 at 10:24
  • I'm not sure that's a permanent solution, you could still be `mv`ing a file without the complete contents yet. It's kind of like adding a `sleep 1` after the event has been detected, it might make the process work more often than not, but it's still open to failure on a slow network transfer, for example. – Matt Aug 23 '13 at 11:31